Given a 2D array, find out if a given node is surrounded - arrays

Given a 2D array where each digit represents a different color, I want to be able to find out if a given node in the array is surrounded completely by one color. For example, in the 2d array below, I want to be able to confirm that the node at [3][3] is completely surrounded by the color represented by "1". Is there an existing common algorithm that accomplishes this?
{{1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 0, 0},
{1, 1, 1, 1, 1, 1, 1, 1},
{1, 2, 2, 2, 2, 1, 1, 0},
{1, 1, 1, 2, 2, 1, 1, 1},
{1, 1, 1, 2, 2, 2, 2, 1},
{1, 1, 1, 1, 1, 2, 1, 1},
{1, 1, 1, 1, 1, 1, 2, 1}}
EDIT: Sorry I am not asking about whether the target node is immediately surrounded. I am asking about whether if you move out from the target node, you can reach the edge of the array without crossing over the boundary color.
My current code is the following, but it's not quite working
let squaresChecked = []
let squareSurrounded = true
let boardSize = 15
let gameBoard = new Array(boardSize)
for(let i=0; i<gameBoard.length; i++){
gameBoard[i] = Array(boardSize).fill('white')
}
checkSurrounded(x, y, boundaryColor){
if(x >= boardSize || y >= boardSize || x < 0 || y < 0){
squareSurrounded = false
return
}
if(gameBoard[x][y] === boundaryColor){return}
if(squaresChecked.includes(x + ' ' + y)){return}
squaresChecked.push(x + ' ' + y)
checkSurrounded(x+1, y, boundaryColor)
checkSurrounded(x-1, y, boundaryColor)
checkSurrounded(x, y+1, boundaryColor)
checkSurrounded(x, y-1, boundaryColor)
}

This should check for top, left, right, bottom for given cell at row,col in 2D array if surrounded by var surroundedBy (1).
row = 2
col = 2
arr = [[1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1],
[1, 2, 2, 2, 2, 1, 1, 0],
[1, 1, 1, 2, 2, 1, 1, 1],
[1, 1, 1, 2, 2, 2, 2, 1],
[1, 1, 1, 1, 1, 2, 1, 1],
[1, 1, 1, 1, 1, 1, 2, 1]]
surroundedBy = 1
if(arr[row-1][col] ===surroundedBy && arr[row+1][col] === surroundedBy && arr[row][col - 1] === surroundedBy && arr[row][col + 1] === surroundedBy) {
console.log('surrounded');
}else{
console.log('not surrounded');
}

Related

Identify rows of one numpy array that gave rise to another numpy array

I think I'm missing something obvious. Consider the following code:
import numpy as np
a = np.array([[ 0, 2, 0, 5, 4, 6, 2, 4],
[ 3, 4, 0, 1, 0, 7, 4, 6],
[ 2, 6, 3, 5, 2, 5, 5, 8],
[ 0, 1, 0, 8, 0, 5, 8, 10],
[ 7, 9, 2, 7, 0, 6, 7, 2],
[ 0, 1, 4, 9, 0, 7, 9, 9],
[ 0, 6, 7, 5, 6, 2, 4, 13],
[ 0, 1, 1, 4, 1, 3, 2, 3]]
# isolate columns 2,3,6,7
mask = [False,False, True, True,False,False, True, True]
b = a[:,mask]
# determine rows of b having unique elements
s = np.sort(b, axis=1)
c = b[~(s[:,:-1] == s[:,1:]).any(1)]
c looks like:
c = [[ 0, 5, 2, 4],
[ 0, 1, 4, 6],
[ 7, 5, 4, 13],
[ 1, 4, 2, 3]]
QUESTION: How do I 'recover' the rows of a that gave rise to the rows of c?
The output should be like:
d = [[ 0, 2, 0, 5, 4, 6, 2, 4],
[ 3, 4, 0, 1, 0, 7, 4, 6],
[ 0, 6, 7, 5, 6, 2, 4, 13],
[ 0, 1, 1, 4, 1, 3, 2, 3]]

Most efficient way to select elements in n dimension array in Ruby with indexes

I want to select elements with its indexes based on given condition for n dimension array
I have solution for two dimension array like below
ary = [
['A', 'B', 'C'],
['D', 'E', 'F'],
['G', 'H', 'I']
]
new_ary = ary.collect.with_index do |row, index_r|
row.collect.with_index { |col, index_c| [col, index_r, index_c] if index_c == 0 }.compact
end
new_ary.flatten(1)
=> [["A", 0, 0], ["D", 1, 0], ["G", 2, 0]]
I want this solution for n dimension
it would be great if method works like this
ary.select_with_indexes { |val, index_c ,index_c,...| index_c == 0 }
# x,y,... is indexes
# val is value of x,y,... index
# x == 0 is condition for select element, this condition is only for understanding. we will put any condition there
Three dimension array like below
ary = [[
['A1', 'B1', 'C1'],
['D1', 'E1', 'F1'],
['G1', 'H1', 'I1']
],[
['A2', 'B2', 'C2'],
['D2', 'E2', 'F2'],
['G2', 'H2', 'I2']
],[
['A3', 'B3', 'C3'],
['D3', 'E3', 'F3'],
['G3', 'H3', 'I3']
]]
new_ary = ary.collect.with_index do |row, index_r|
row.collect.with_index do |col, index_c|
col.collect.with_index do |val, index_d|
[val, index_r, index_c, index_d] if index_d == 0
end.compact
end
end
new_ary.flatten(1)
=> [[["A1", 0, 0, 0]], [["D1", 0, 1, 0]], [["G1", 0, 2, 0]], [["A2", 1, 0, 0]], [["D2", 1, 1, 0]], [["G2", 1, 2, 0]], [["A3", 2, 0, 0]], [["D3", 2, 1, 0]], [["G3", 2, 2, 0]]]
index_d == 0 this condition is only for understanding
we will put any condition there
Code
In the examples in the question the index of the innermost array is always zero. I have made that an argument, most_inner_index.
def doit(ary, most_inner_index)
first, *rest = nested_indices(ary)
first.product(*rest).map do |indices|
[ary.dig(*indices, most_inner_index), *indices, most_inner_index]
end
end
def nested_indices(ary)
sizes = []
while ary.first.is_a?(Array)
sizes << ary.size.times.to_a
ary = ary.first
end
sizes
end
Examples
ary2 = [
['A', 'B', 'C'],
['D', 'E', 'F'],
['G', 'H', 'I']
]
doit(ary2, 0)
#=> [["A", 0, 0], ["D", 1, 0], ["G", 2, 0]]
doit(ary2, 1)
#=> [["B", 0, 1], ["E", 1, 1], ["H", 2, 1]]
doit(ary2, 2)
#=> [["C", 0, 2], ["F", 1, 2], ["I", 2, 2]]
ary3 = [[
['A1', 'B1', 'C1'],
['D1', 'E1', 'F1'],
['G1', 'H1', 'I1']
],[
['A2', 'B2', 'C2'],
['D2', 'E2', 'F2'],
['G2', 'H2', 'I2']
],[
['A3', 'B3', 'C3'],
['D3', 'E3', 'F3'],
['G3', 'H3', 'I3']
]]
doit(ary3, 0)
#=> [["A1", 0, 0, 0], ["D1", 0, 1, 0], ["G1", 0, 2, 0],
# ["A2", 1, 0, 0], ["D2", 1, 1, 0], ["G2", 1, 2, 0],
# ["A3", 2, 0, 0], ["D3", 2, 1, 0], ["G3", 2, 2, 0]]
doit(ary3, 1)
#=> [["B1", 0, 0, 1], ["E1", 0, 1, 1], ["H1", 0, 2, 1],
# ["B2", 1, 0, 1], ["E2", 1, 1, 1], ["H2", 1, 2, 1],
# ["B3", 2, 0, 1], ["E3", 2, 1, 1], ["H3", 2, 2, 1]]
doit(ary3, 2)
#=> [["C1", 0, 0, 2], ["F1", 0, 1, 2], ["I1", 0, 2, 2],
# ["C2", 1, 0, 2], ["F2", 1, 1, 2], ["I2", 1, 2, 2],
# ["C3", 2, 0, 2], ["F3", 2, 1, 2], ["I3", 2, 2, 2]]
Notice that the return values are not quite in the form desired. That is because I could not figure out from the question how many nested arrays were desired.
ary4 = [
[
[
[['A1', 'B1'], ['C1', 'D1']],
[['E1', 'F1'], ['G1', 'H1']]
],
[
[['I1', 'J1'], ['K1', 'L1']],
[['M1', 'N1'], ['O1', 'P1']]
]
],
[
[
[['A2', 'B2'], ['C2', 'D2']],
[['E2', 'F2'], ['G2', 'H2']]
],
[
[['I2', 'J2'], ['K2', 'L2']],
[['M2', 'N2'], ['O2', 'P2']]
]
],
[
[
[['A3', 'B3'], ['C3', 'D3']],
[['E3', 'F3'], ['G3', 'H3']]
],
[
[['I3', 'J3'], ['K3', 'L3']],
[['M3', 'N3'], ['O3', 'P3']]
]
]
]
doit(ary4, 0)
#=> [["A1", 0, 0, 0, 0, 0], ["C1", 0, 0, 0, 1, 0], ["E1", 0, 0, 1, 0, 0],
# ["G1", 0, 0, 1, 1, 0], ["I1", 0, 1, 0, 0, 0], ["K1", 0, 1, 0, 1, 0],
# ["M1", 0, 1, 1, 0, 0], ["O1", 0, 1, 1, 1, 0], ["A2", 1, 0, 0, 0, 0],
# ["C2", 1, 0, 0, 1, 0], ["E2", 1, 0, 1, 0, 0], ["G2", 1, 0, 1, 1, 0],
# ["I2", 1, 1, 0, 0, 0], ["K2", 1, 1, 0, 1, 0], ["M2", 1, 1, 1, 0, 0],
# ["O2", 1, 1, 1, 1, 0], ["A3", 2, 0, 0, 0, 0], ["C3", 2, 0, 0, 1, 0],
# ["E3", 2, 0, 1, 0, 0], ["G3", 2, 0, 1, 1, 0], ["I3", 2, 1, 0, 0, 0],
# ["K3", 2, 1, 0, 1, 0], ["M3", 2, 1, 1, 0, 0], ["O3", 2, 1, 1, 1, 0]]
doit(ary4, 1)
#=> [["B1", 0, 0, 0, 0, 1], ["D1", 0, 0, 0, 1, 1], ["F1", 0, 0, 1, 0, 1],
# ["H1", 0, 0, 1, 1, 1], ["J1", 0, 1, 0, 0, 1], ["L1", 0, 1, 0, 1, 1],
# ["N1", 0, 1, 1, 0, 1], ["P1", 0, 1, 1, 1, 1], ["B2", 1, 0, 0, 0, 1],
# ["D2", 1, 0, 0, 1, 1], ["F2", 1, 0, 1, 0, 1], ["H2", 1, 0, 1, 1, 1],
# ["J2", 1, 1, 0, 0, 1], ["L2", 1, 1, 0, 1, 1], ["N2", 1, 1, 1, 0, 1],
# ["P2", 1, 1, 1, 1, 1], ["B3", 2, 0, 0, 0, 1], ["D3", 2, 0, 0, 1, 1],
# ["F3", 2, 0, 1, 0, 1], ["H3", 2, 0, 1, 1, 1], ["J3", 2, 1, 0, 0, 1],
# ["L3", 2, 1, 0, 1, 1], ["N3", 2, 1, 1, 0, 1], ["P3", 2, 1, 1, 1, 1]]
Explanation
The steps are as follows for ary3 and most_inner_index = 0.
a = nested_indices(ary3)
#=> [[0, 1, 2], [0, 1, 2]]
first, *rest = a
#=> [[0, 1, 2], [0, 1, 2]]
Ruby applies array decomposition to obtain the following.
first
#=> [0, 1, 2]
rest
#=> [[0, 1, 2]]
Continuing,
b = first.product(*rest)
#=> [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]]
c = b.map do |indices|
[ary.dig(*indices, most_inner_index), *indices, most_inner_index]
end
#=> [["A1", 0, 0, 0], ["D1", 0, 1, 0], ["G1", 0, 2, 0],
# ["A2", 1, 0, 0], ["D2", 1, 1, 0], ["G2", 1, 2, 0],
# ["A3", 2, 0, 0], ["D3", 2, 1, 0], ["G3", 2, 2, 0]]
See Array#product and Array#dig.

How to get depth of tree of arrays given total num items and max array size?

Given this divide algorithm and sample data:
const data = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 0
]
function divide(data, size) {
const result = []
for (let i = 0; i < data.length; i += size) {
const chunk = data.slice(i, i + size);
result.push(chunk)
}
if (result.length > size) {
return divide(result, size)
}
return result;
}
const result = divide(data, 5);
console.log(result)
How do you calculate the number of levels in the resulting tree? In this case of block size 5, I think there are 3 are 4 levels about, but what is the equation to use so you don't have to compute the actual tree? Basically getDepth(numItems, blockSize)?
Every recursive call reduces the input size by a factor of blocksize.
Starting with your example of 100 items. This is grouped into 20, these 20 are grouped into 4 and the algorithm ends.
The expression that capture this is log with a base of blocksize.
f(n,m) = ceil(log_base_m(n))
The depth of the example tree is
        ceil(log5(99))
In general:
        ceil(logchunksize(datasize-1))

How to subtract arrays of integers

I have four arrays of int:
num_defect = [30, 30, 20, 20, 18, 18, 5, 5]
num_fixes = [1, 0, 3, 2, 1, 2, 2, 2]
num_blocks = [0, 0, 0, 0, 2, 2, 1, 0]
num_ext_defects = [1, 1, 0, 0, 2, 2, 2, 1]
I want to display the number of open defects, which is given by:
num_defects - num_fixes - num_blocks - num_ext_defects
So for the reporting, num_defects should now contain:
[28, 29, 17, 13, 12, 0, 2]
I tried:
num_defect.map { |i| i - num_fixes[i] - num_blocks[i] - num_ext_defects[i] }
but it raises:
nil can't be coerced into Fixnum
Any help greatly appreciated.
With
num_defect.map { |i|
i is the element of the array, not its index. If you want your map to work correctly, you'll need an index as well:
num_defect.map.with_index do |element, index|
element - num_fixes[index] - num_blocks[index] - num_ext_defects[index]
end
Use map! instead of map in order to mutate num_defect.
Or if you'd like a nicer version:
a = [30,30,20,20,18,18,5,5]
b = [ 1, 0, 3, 2, 1, 2,2,2]
c = [ 0, 0, 0, 0, 2, 2,1,0]
d = [ 1, 1, 0, 0, 2, 2,2,1]
a.zip(b,c,d).map { |arr| arr.inject(:-) }
# => [28, 29, 17, 18, 13, 12, 0, 2]
If i understand you correctly you might be looking for an array method called each_index.
num_defect.each_index do |i|
num_defect[i] -= num_fixes[i] + num_blocks[i] + num_ext_defects[i]
end
require 'matrix'
(Vector.elements(num_defect) - Vector.elements(num_fixes) -
Vector.elements(num_blocks) - Vector.elements(num_ext_defects)).to_a
#=> [28, 29, 17, 18, 13, 12, 0, 2]
This uses the methods Vector::elements and Vector#to_a. One could write Vector[*arr] in place of Vector.elements(arr), using Vector::[].
If num_defect is to be mutated, you could write num_defect.replace(<above expression>). If
arr = [num_defect, num_fixes, num_blocks, num_ext_defects]
#=> [[30, 30, 20, 20, 18, 18, 5, 5],
# [ 1, 0, 3, 2, 1, 2, 2, 2],
# [ 0, 0, 0, 0, 2, 2, 1, 0],
# [ 1, 1, 0, 0, 2, 2, 2, 1]]
one could use matrix multiplication:
(Matrix.row_vector([1, *[-1]*(arr.size-1)]) * Matrix.rows(arr)).to_a.first
#=> [28, 29, 17, 18, 13, 12, 0, 2]
where
[1, *[-1]*(arr.size-1)]
#=> [1, -1, -1, -1]
This would be convenient and relatively computationally-efficient if arr had a larger number of elements than it does in the example.
This uses the Matrix methods Matrix::row_vector, Matrix::rows and Matrix#to_a. One could write Matrix[*arr] in place of Matrix.rows(arr), using Matrix::[]. One advantage of using rows, however, is that one can add the argument false (Matrix.rows(arr, false)) to avoid copying the elements of arr in the creation of the Matrix object.
[num_defect, num_fixes, num_blocks, num_ext_defects]
.transpose
.map{|first, *rest| first - rest.sum}
# => [28, 29, 17, 18, 13, 12, 0, 2]
Using Enumerator#each_with_object:
num_defect.each_with_index.with_object([]){ |(e, i), a| a << (e - num_fixes[i] - num_blocks[i] - num_ext_defects[i]) }
#=> [28, 29, 17, 18, 13, 12, 0, 2]

Pad an array with 0's swift [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I am attempting to pad an an array with zeros but cannot find a succinct way to do this in swift.
If I have array x = [1,2,3 ; 4,5,6 ; 7,8,9]
in matlab I could use the command
y = [zeros(1,3+2);zeros(3,1),x,zeros(3,1);zeros(1,3+2)]
giving the desired output array of [0,0,0,0,0; 0,1,2,3,0 ; 0,4,5,6,0 ; 0,7,8,9,0 ; 0,0,0,0,0]
However so far in a swift playground I have only been able to refer to each element individually to correctly form the new array.
The methods I have tried so far using x as the input and y as the output, the first similar to matlab,
var x = [[1,2,3,],[4,5,6],[7,8,9]]
var y = [[0,0,0,0,0],[0,x[0],0],[0,x[1],0],[0,x[2],0],[0,0,0,0,0]]
The second being a loop
for i in 0 ..< x.count + 1 {
if i == 0 || i == x.count - 1 {
y[i] = [0,0,0,0,0]
}
else{
y[i] = [0, x[i-1] ,0]
}
}
Rather than looking like a standard array in the Xcode playground preview this is the output given.
[[0, 0, 0, 0, 0], [0, […], 0], [0, 0, 0, 0, 0], [0, […], 0], [0, 0, 0, 0, 0]]
which also prints to the console very strangely, using the code
for i in 0 ..< y.count {
print("\(y[i])")
}
the output is
(
0,
0,
0,
0,
0
)
(
0,
(
1,
2,
3
),
0
)
(
0,
0,
0,
0,
0
)
(
0,
(
7,
8,
9
),
0
)
(
0,
0,
0,
0,
0
)
as opposed to the expected
[0, 0, 0, 0, 0]
[0, 1, 2, 3, 0]
[0, 4, 5, 6, 0]
[0, 7, 8, 9, 0]
[0, 0, 0, 0, 0]
What is the best way to do this?
I made a generic version of appzYourLife's answer that can take any arbitrary nested array type. It also adds support for top and bottom padding
extension Array where Element: _ArrayType {
typealias InnerElement = Element.Generator.Element
func pad2DArray(with padding: InnerElement,
top: Int = 0, left: Int = 0,
right: Int = 0, bottom: Int = 0) -> [[InnerElement]] {
let newHeight = self.count + top + bottom
let newWidth = (self.first?.count ?? 0) + left + right
var paddedArray = [[InnerElement]](count: newHeight, repeatedValue:
[InnerElement](count: newWidth, repeatedValue: padding))
for (rowIndex, row) in self.enumerate() {
for (columnIndex, element) in row.enumerate() {
paddedArray[rowIndex + top][columnIndex + left] = element
}
}
return paddedArray
}
}
var input = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
let result = input.pad2DArray(with: 0, top: 1, left: 1, right: 1, bottom: 1)
/*
result:
[
[0, 0, 0, 0, 0],
[0, 1, 2, 3, 0],
[0, 4, 5, 6, 0],
[0, 7, 8, 9, 0],
[0, 0, 0, 0, 0],
]
*/
Extension
If you define this extension
extension _ArrayType where Element == Int {
func pad(left left: Int, right: Int) -> [Int] {
let leftSide = [Int](count: left, repeatedValue: 0)
let rightSide = [Int](count: right, repeatedValue: 0)
return leftSide + (self as! [Int]) + rightSide
}
}
you can then write
[1,2,3].pad(left: 1, right: 1) // [0, 1, 2, 3, 0]
Definitely not as elegant as the accepted answer, but it works nonetheless:
var x = [[1,2,3,],[4,5,6],[7,8,9]]
var y = [[Int]]()
y.insert([0,0,0,0,0], atIndex: 0)
for i in 0 ..< x.count {
var intArray: [Int] = []
for number in x[i] {
intArray.append(number)
}
intArray.insert(0, atIndex: 0)
intArray.insert(0, atIndex: intArray.count)
y.append(intArray)
}
y.insert([0,0,0,0,0], atIndex: x.count + 1)
The output from
for i in 0 ..< y.count {
print("\(y[i])")
}
is
[0, 0, 0, 0, 0]
[0, 1, 2, 3, 0]
[0, 4, 5, 6, 0]
[0, 7, 8, 9, 0]
[0, 0, 0, 0, 0]

Resources