I have a two-dimensional array, say
我有一个二维数组
0 0 0 0 0
0 2 3 4 0
0 9 1 5 0
0 8 7 6 0
0 0 0 0 0
And i need to get all the numbers adjacent to 1(2, 3, 4, 5, 6, 7, 8, 9)
我需要得到1(2 3 4 5 6 7 8 9)
Is there a less ugly solution than:
有没有比:
topLeft = array[x-1][y-1]
top = array[x][y-1]
topRight = array[x+1][y-1]
# etc
Thanks!
谢谢!
5 个解决方案
#1
18
If you're not worried about the order, the cleanest is probably to use a couple of loops:
如果你不担心订单,最干净的可能是使用几个循环:
result = new List<int>(8);
for (dx = -1; dx <= 1; ++dx) {
for (dy = -1; dy <= 1; ++dy) {
if (dx != 0 || dy != 0) {
result.Add(array[x + dx][y + dy]);
}
}
}
If the order is important, you can construct a list of all the (dx, dy) in the order you want and iterate over that instead.
如果顺序很重要,您可以按照您想要的顺序构造一个所有(dx, dy)的列表,并对其进行迭代。
As pointed out in the comments, you probably want to add boundary checks. You could do that like this (assuming order doesn't matter):
正如评论中指出的,您可能需要添加边界检查。你可以这样做(假设顺序无关):
List<int> result = new List<int>(8);
for (int dx = (x > 0 ? -1 : 0); dx <= (x < max_x ? 1 : 0); ++dx)
{
for (int dy = (y > 0 ? -1 : 0); dy <= (y < max_y ? 1 : 0); ++dy)
{
if (dx != 0 || dy != 0)
{
result.Add(array[x + dx][y + dy]);
}
}
}
#2
11
I'd probably go for a constant list of dx, dy for each direction, like so:
我可能会得到一个常数的dx,每个方向的dy,像这样:
struct {
int dx;
int dy;
} directions[] = {{-1,-1,},{-1,0,},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};
Then you'd iterate over the directions using a simple loop:
然后用一个简单的循环遍历方向:
for (int i = 0; i < 8; i++) {
// use x + directions[i].dx;
// use y + directions[i].dy;
}
You can of course use sizeof(directions) / sizeof(directions[1])
instead of the 8
above.
你当然可以使用sizeof(方向)/ sizeof(方向[1])代替上面的8。
#3
7
personally, the loops are more ugly than the original.
就个人而言,这些循环比原来的更难看。
topLeft = array[ x - 1 ][ y - 1 ]
top = array[ x ][ y - 1 ]
topRight = array[ x + 1 ][ y - 1 ]
midLeft = array[ x - 1 ][ y ]
midRight = array[ x + 1 ][ y ]
botLeft = array[ x - 1 ][ y + 1 ]
bot = array[ x ][ y + 1 ]
botRight = array[ x + 1 ][ y + 1 ]
But without specifying what you want the values for - what you do in the different directions implies whether you want the values in separate variables or not.
但是,在不指定值的情况下——在不同方向上的操作意味着您是否希望这些值位于不同的变量中。
For game of life style processing, you usually want to be working on a bitpattern anyway rather than an array of individual values, and you can scan horizontally inspecting only three of the eight cells at a time using accumulators and temporaries. For graphics convolutions, use an existing library with a 3x3 kernel.
对于生活方式处理游戏,您通常希望处理位模式,而不是单个值的数组,并且您可以使用累加器和临时器一次水平地检查8个单元中的3个。对于图形卷积,使用现有的库和3x3内核。
The other way of dealing with boundaries is to expand the array by one cell in each direction. This avoids expensive branches in the convolution code.
另一种处理边界的方法是在每个方向上用一个单元格展开阵列。这避免了在卷积代码中使用昂贵的分支。
#4
1
In C++
this can look like:
在c++中,这看起来像:
vector<int> adj;
for (int i = 0; i < 9; i++)
if (i != 4) adj.push_back(array[x + i/3 - 1][y + i%3 - 1]);
This is not very clear solution but very short.
这不是很明确的解决办法,但很短。
#5
0
Here's a Ruby solution. The algorithm should be evident even for readers who are not familiar with Ruby.
这是一个Ruby的解决方案。即使对于不熟悉Ruby的读者,算法也应该是显而易见的。
def adjacent(arr, r, c)
last_row, last_col = arr.size-1, arr.first.size-1
([r-1,0].max..[r+1,last_row].min).each_with_object([]) do |i, a|
([c-1,0].max..[c+1,last_col].min).each { |j| a << arr[i][j] unless i==r && j==c }
end
end
arr = [
[-1, 2, 3, 4],
[-2, 9, 1, 5],
[-3, 8, 7, 6],
[-4, -5, -6, -7]
]
(0..2).each do |i|
(1..3).each do |j|
puts "adjacent to #{arr[i][j]} at r=#{i}, c=#{j} = #{adjacent(arr, i, j)}"
end
end
prints
打印
adjacent to 2 at r=0, c=1 = [-1, 3, -2, 9, 1]
adjacent to 3 at r=0, c=2 = [2, 4, 9, 1, 5]
adjacent to 4 at r=0, c=3 = [3, 1, 5]
adjacent to 9 at r=1, c=1 = [-1, 2, 3, -2, 1, -3, 8, 7]
adjacent to 1 at r=1, c=2 = [2, 3, 4, 9, 5, 8, 7, 6]
adjacent to 5 at r=1, c=3 = [3, 4, 1, 7, 6]
adjacent to 8 at r=2, c=1 = [-2, 9, 1, -3, 7, -4, -5, -6]
adjacent to 7 at r=2, c=2 = [9, 1, 5, 8, 6, -5, -6, -7]
adjacent to 6 at r=2, c=3 = [1, 5, 7, -6, -7]
#1
18
If you're not worried about the order, the cleanest is probably to use a couple of loops:
如果你不担心订单,最干净的可能是使用几个循环:
result = new List<int>(8);
for (dx = -1; dx <= 1; ++dx) {
for (dy = -1; dy <= 1; ++dy) {
if (dx != 0 || dy != 0) {
result.Add(array[x + dx][y + dy]);
}
}
}
If the order is important, you can construct a list of all the (dx, dy) in the order you want and iterate over that instead.
如果顺序很重要,您可以按照您想要的顺序构造一个所有(dx, dy)的列表,并对其进行迭代。
As pointed out in the comments, you probably want to add boundary checks. You could do that like this (assuming order doesn't matter):
正如评论中指出的,您可能需要添加边界检查。你可以这样做(假设顺序无关):
List<int> result = new List<int>(8);
for (int dx = (x > 0 ? -1 : 0); dx <= (x < max_x ? 1 : 0); ++dx)
{
for (int dy = (y > 0 ? -1 : 0); dy <= (y < max_y ? 1 : 0); ++dy)
{
if (dx != 0 || dy != 0)
{
result.Add(array[x + dx][y + dy]);
}
}
}
#2
11
I'd probably go for a constant list of dx, dy for each direction, like so:
我可能会得到一个常数的dx,每个方向的dy,像这样:
struct {
int dx;
int dy;
} directions[] = {{-1,-1,},{-1,0,},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};
Then you'd iterate over the directions using a simple loop:
然后用一个简单的循环遍历方向:
for (int i = 0; i < 8; i++) {
// use x + directions[i].dx;
// use y + directions[i].dy;
}
You can of course use sizeof(directions) / sizeof(directions[1])
instead of the 8
above.
你当然可以使用sizeof(方向)/ sizeof(方向[1])代替上面的8。
#3
7
personally, the loops are more ugly than the original.
就个人而言,这些循环比原来的更难看。
topLeft = array[ x - 1 ][ y - 1 ]
top = array[ x ][ y - 1 ]
topRight = array[ x + 1 ][ y - 1 ]
midLeft = array[ x - 1 ][ y ]
midRight = array[ x + 1 ][ y ]
botLeft = array[ x - 1 ][ y + 1 ]
bot = array[ x ][ y + 1 ]
botRight = array[ x + 1 ][ y + 1 ]
But without specifying what you want the values for - what you do in the different directions implies whether you want the values in separate variables or not.
但是,在不指定值的情况下——在不同方向上的操作意味着您是否希望这些值位于不同的变量中。
For game of life style processing, you usually want to be working on a bitpattern anyway rather than an array of individual values, and you can scan horizontally inspecting only three of the eight cells at a time using accumulators and temporaries. For graphics convolutions, use an existing library with a 3x3 kernel.
对于生活方式处理游戏,您通常希望处理位模式,而不是单个值的数组,并且您可以使用累加器和临时器一次水平地检查8个单元中的3个。对于图形卷积,使用现有的库和3x3内核。
The other way of dealing with boundaries is to expand the array by one cell in each direction. This avoids expensive branches in the convolution code.
另一种处理边界的方法是在每个方向上用一个单元格展开阵列。这避免了在卷积代码中使用昂贵的分支。
#4
1
In C++
this can look like:
在c++中,这看起来像:
vector<int> adj;
for (int i = 0; i < 9; i++)
if (i != 4) adj.push_back(array[x + i/3 - 1][y + i%3 - 1]);
This is not very clear solution but very short.
这不是很明确的解决办法,但很短。
#5
0
Here's a Ruby solution. The algorithm should be evident even for readers who are not familiar with Ruby.
这是一个Ruby的解决方案。即使对于不熟悉Ruby的读者,算法也应该是显而易见的。
def adjacent(arr, r, c)
last_row, last_col = arr.size-1, arr.first.size-1
([r-1,0].max..[r+1,last_row].min).each_with_object([]) do |i, a|
([c-1,0].max..[c+1,last_col].min).each { |j| a << arr[i][j] unless i==r && j==c }
end
end
arr = [
[-1, 2, 3, 4],
[-2, 9, 1, 5],
[-3, 8, 7, 6],
[-4, -5, -6, -7]
]
(0..2).each do |i|
(1..3).each do |j|
puts "adjacent to #{arr[i][j]} at r=#{i}, c=#{j} = #{adjacent(arr, i, j)}"
end
end
prints
打印
adjacent to 2 at r=0, c=1 = [-1, 3, -2, 9, 1]
adjacent to 3 at r=0, c=2 = [2, 4, 9, 1, 5]
adjacent to 4 at r=0, c=3 = [3, 1, 5]
adjacent to 9 at r=1, c=1 = [-1, 2, 3, -2, 1, -3, 8, 7]
adjacent to 1 at r=1, c=2 = [2, 3, 4, 9, 5, 8, 7, 6]
adjacent to 5 at r=1, c=3 = [3, 4, 1, 7, 6]
adjacent to 8 at r=2, c=1 = [-2, 9, 1, -3, 7, -4, -5, -6]
adjacent to 7 at r=2, c=2 = [9, 1, 5, 8, 6, -5, -6, -7]
adjacent to 6 at r=2, c=3 = [1, 5, 7, -6, -7]