我有{ -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语句吗?
答案 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();
}
<强>输出强>