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]]
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.
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))
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]
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]