迭代一组不均匀的数字

时间:2018-01-19 16:37:13

标签: c# loops set

我有{ -1, 0, +1 }形式的一组数字,我必须使用两个循环迭代,就像使用2D数组时一样。

然后整个集合成为上述数字的每个组合: { -1, -1 } -> { +1, +1 },总共9个。

但是,我必须跳过集合{ 0, 0 }。通常我会用if语句检查,但是在两个嵌套循环中使用它会使它在每次运行时检查这个条件。

有没有一种有效的方法可以做到这一点?

更新:我觉得这值得更多细节,因为这个问题可能与我上面要做的完全不同。

检查阵列中的相邻单元格是基本的。所以{ 0, 0 }是我们正在检查的细胞,但我希望检查与其相邻的每个细胞,不包括主细胞。

想象一下,我们有一个2D数组int[,] array = new int[,] { ... }; 如果我们然后在大约中间的任何索引处访问数组(不接近任何边索引;如底部/顶部行或底部/顶部列),我们的概念鸟的数组视图将会看起来像这样:

[-1, -1] [-1, 0] [-1, +1]
[0, -1] [0, 0] [0, +1]
[+1, -1] [+1, 0] [+1, +1]

[0,0]是我们当前的元素。我们可以使用[行,列]的上述数字访问每个相邻的元素/单元格。

执行此操作的典型循环如下所示:

for (int i = row-1; i <= row+1; ++i) {
    for (int j = col-1; j <= col+1; ++j) {
        if (i == row && j == col) continue;
            ...
    }
}

我们可以避免使用if语句吗?

3 个答案:

答案 0 :(得分:1)

只需计算每一对,然后从最终集中删除要排除的一对。 [良好实现]集合专门用于高效删除(无论如何更有效,基于散列的集合为O(1),基于树的集合为O(log(n)),因此比检查每个单值更快在集合中,这是你在循环中进行检查所要做的。

答案 1 :(得分:1)

编辑完成后,您似乎根本不需要循环,并且您想要的结果有8个明确定义的元素。

因此,您只需创建一个小方法,将所有相邻单元格提供给主单元格:

Point[] GetAdjacentPoints(Point p)
{
    return new[]{
        new Point { X = p.X - 1, Y = p.Y - 1 },
        new Point { X = p.X,     Y = p.Y - 1 },
        new Point { X = p.X + 1, Y = p.Y - 1 },
        new Point { X = p.X - 1, Y = p.Y },
        // leave out p itself
        new Point { X = p.X + 1, Y = p.Y },
        new Point { X = p.X - 1, Y = p.Y + 1},
        new Point { X = p.X,     Y = p.Y + 1},
        new Point { X = p.X + 1, Y = p.Y + 1}
    };
}

(我假设Point类似于struct Point {public int X {get;set;} public int Y {get;set;}}或任何其他类型来保存两个整数。

您可以像这样使用此方法:

foreach(Point adjacent in GetAdjacentPoints(new Point {X = 0, Y = 0})
    Console.WriteLine($"X: {adjacent.X} Y: {adjacent.Y}");

输出:

X: -1 Y: -1
X: 0 Y: -1
X: 1 Y: -1
X: -1 Y: 0
X: 1 Y: 0
X: -1 Y: 1
X: 0 Y: 1
X: 1 Y: 1

答案 2 :(得分:1)

我建议您先测量一下,然后看看这是否真的有问题,因为根据您使用的收藏类型,Add操作可能比if更昂贵声明(在我的情况下,它包括创建一个新列表,然后将该列表添加到另一个列表)。

例如,使用List<int>来保存原始集,使用List<List<int>>来保存组合,我发现使用if语句 更快 比没有使用它(如果我们不使用它,那么我们仍然需要迭代对来找到我们想要删除的那些)。

以下是我运行的测试,使用 if if的循环,其中包含2001项(来自-1000到1000),它创建了总共4004000个集合。我在循环中运行测试100次并显示平均时间以尝试获得最准确的结果:

private static void Main()
{
    var items = Enumerable.Range(-1000, 2001).ToList();
    var combinations = new List<List<int>>();
    var withIfCount = new List<long>();
    var withoutIfCount = new List<long>();
    var sw = new Stopwatch();

    // Both test are run 100 times
    for (int count = 0; count < 100; count++)
    {
        sw.Restart();
        for (int outer = 0; outer < items.Count; outer++)
        {
            for (int inner = 0; inner < items.Count; inner++)
            {
                if (outer == 0 && inner == 0) continue;
                combinations.Add(new List<int> {outer, inner});
            }
        }
        sw.Stop();
        withIfCount.Add(sw.ElapsedMilliseconds);
        combinations.Clear();

        sw.Restart();
        for (int outer = 0; outer < items.Count; outer++)
        {
            for (int inner = 0; inner < items.Count; inner++)
            {
                combinations.Add(new List<int> {outer, inner});
            }
        }
        sw.Stop();
        withoutIfCount.Add(sw.ElapsedMilliseconds);
        combinations.Clear();
    }

    // Display averages
    Console.WriteLine("Average time with 'if': " + withIfCount.Average());
    Console.WriteLine("Average time without 'if': " + withoutIfCount.Average());

    Console.WriteLine("\nDone!\nPress any key to exit...");
    Console.ReadKey();
}

<强>输出

enter image description here