Slice sets of columns in numpy - arrays

Consider a numpy array as such:
>>> a = np.array([[1, 2, 3, 0, 1], [2, 3, 2, 2, 2], [0, 3, 3, 2, 2]])
>>> a
array([[1, 2, 3, 0, 1],
[2, 3, 2, 2, 2],
[0, 3, 3, 2, 2]])
And an array which contains couples of column indexes to slice (a specific column can appear in multiple couples):
b = [[0,1], [0,3], [1,4]]
How can I slice/broadcast/stride a using b to get a result as such:
array([[[1, 2],
[2, 3],
[0, 3]],
[[1, 0],
[2, 2],
[0, 2]],
[[2, 1],
[3, 2],
[3, 2]]])

Use b as column indices to subset the array and then transpose the result:
a[:, b].swapaxes(0, 1)
# array([[[1, 2],
# [2, 3],
# [0, 3]],
# [[1, 0],
# [2, 2],
# [0, 2]],
# [[2, 1],
# [3, 2],
# [3, 2]]])

Related

How to zip every element of array to every element of another array in ruby?

Say I have this array:
[0, 1, 4], [2, 3]
How can I merge them to get:
[0,2], [0,3], [1,2], [1,3], [4,2], [4,3]
I tried:
[0, 1, 4].zip [2, 3]
But I got:
[[0, 2], [1, 3], [4, nil]]
Any ideas?
[0, 1, 4].product([2, 3])
That should generate:
[[0, 2], [0, 3], [1, 2], [1, 3], [4, 2], [4, 3]]

Summing elements from arrays with matching elements

I have an array that looks like this:
original = [[1, 2, 3], [2, 2, 2], [1, 2, 3], [2, 2, 2], [2, 2, 3], [1, 2, 2], [5, 4, 2]]
I'd like to get a new array whose elements that match the second and third position would sum up its first position to get this:
expected_output = [[4, 2, 3], [5, 2, 2], [5, 4, 2]]
I got to grouping the elements from the array as follows:
new_array = original.group_by {|n| n[1] && n[2] }
# => {3=>[[1, 2, 3], [1, 2, 3], [2, 2, 3]], 2=>[[2, 2, 2], [2, 2, 2], [1, 2, 2], [5, 4, 2]]}
It is still far from my desired output.
Here's one way to return a new array of arrays where the first element of each array is the sum of the original array's first element where its second and third elements match:
arr = [[1, 2, 3], [2, 2, 2], [1, 2, 3], [2, 2, 2], [2, 2, 3], [1, 2, 2], [5, 4, 2]]
array_groups = arr.group_by { |sub_arr| sub_arr[1, 2] }
result = array_groups.map do |k, v|
k.unshift(v.map(&:first).inject(:+))
end
result
# => [[4, 2, 3], [5, 2, 2], [5, 4, 2]]
Hope this helps!
This will produce a similar result using an array grouping rather than combining the two latter numbers.
original = [[1, 2, 3], [2, 2, 2], [1, 2, 3], [2, 2, 2], [2, 2, 3], [1, 2, 2], [5, 4, 2]]
new = original.group_by {|n| [n[1], n[2]] }
added = new.map{|x| [new[x.first].map(&:first).inject(0, :+),x.first].flatten}
puts added.to_s
original.each_with_object(Hash.new(0)) { |(f,*rest),h| h[rest] += f }.
map { |(s,t),f| [f,s,t] }
# => [[4, 2, 3], [5, 2, 2], [5, 4, 2]]
Note that
original.each_with_object(Hash.new(0)) { |(f,*rest),h| h[rest] += f }
#=> {[2, 3]=>4, [2, 2]=>5, [4, 2]=>5}
Hash.new(0) is sometimes called a counting hash. To understand how that works, see Hash::new, especially the explanation of the effect of providing a default value as an argument of new. In brief, if a hash is defined h = Hash.new(0), then if h does not have a key k, h[k] returns the default value, here 0 (and the hash is not changed).

remove duplicates based on one field in a numpy array

How do I remove duplicates when a numpy array field has duplicates.
for example, i have an array like this:
vals = numpy.array([[1,2,3],[1,5,6],[1,8,7],[0,4,5],[2,2,1],[0,0,0],[5,4,3]])
array([[1, 2, 3],
[1, 5, 6],
[1, 8, 7],
[0, 4, 5],
[2, 2, 1],
[0, 0, 0],
[5, 4, 3]])
i need to remove the duplicates for field [0], so that i got the results like:
([1,2,3],
[0, 4, 5],
[2, 2, 1],
[0, 0, 0],
[5, 4, 3]])
You can use numpy.unique:
In [11]: vals
Out[11]:
array([[1, 2, 3],
[1, 5, 6],
[1, 8, 7],
[0, 4, 5],
[2, 2, 1],
[0, 0, 0],
[5, 4, 3]])
In [12]: unique_keys, indices = np.unique(vals[:,0], return_index=True)
In [13]: vals[indices]
Out[13]:
array([[0, 4, 5],
[1, 2, 3],
[2, 2, 1],
[5, 4, 3]])
To maintain the original order:
In [17]: vals[np.sort(indices)]
Out[17]:
array([[1, 2, 3],
[0, 4, 5],
[2, 2, 1],
[5, 4, 3]])

Joining two ranges into 2d array Ruby

How do I join two ranges into a 2d array as such in ruby? Using zip doesn't provide the result I need.
(0..2) and (0..2)
# should become => [[0,0],[0,1],[0,2], [1,0],[1,1],[1,2], [2,0],[2,1],[2,2]]
Ruby has a built in method for this: repeated_permutation.
(0..2).to_a.repeated_permutation(2).to_a
I'm puzzled. Here it is a day after the question was posted and nobody has suggested the obvious: Array#product:
[*0..2].product [*1..3]
#=> [[0, 1], [0, 2], [0, 3], [1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3]]
range_a = (0..2)
range_b = (5..8)
def custom_join(a, b)
a.inject([]){|carry, a_val| carry += b.collect{|b_val| [a_val, b_val]}}
end
p custom_join(range_a, range_b)
Output:
[[0, 5], [0, 6], [0, 7], [0, 8], [1, 5], [1, 6], [1, 7], [1, 8], [2, 5], [2, 6], [2, 7], [2, 8]]
straight forward solution:
range_a = (0..2)
range_b = (5..8)
def custom_join(a, b)
[].tap{|result| a.map{|i| b.map{|j| result << [i, j]; } } }
end
p custom_join(range_a, range_b)
Output:
[[0, 5], [0, 6], [0, 7], [0, 8], [1, 5], [1, 6], [1, 7], [1, 8], [2, 5], [2, 6], [2, 7], [2, 8]]
Simply, this will do it:
a = (0...2).to_a
b = (0..2).to_a
result = []
a.each { |ae| b.each { |be| result << [ae, be] } }
p result
# => [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2]]

Combinaison ruby Array multidimensionnel to get a Array two dimensional

I have a Array multidimensionnel like:
[[1, 1, 4], [2],[2, 3]]
How to get a combinaison each element except the combinaison in the same array: [1, 1],[1, 4],[2, 3]
I want to get:
[1, 2],[1, 3],[4, 2],[4, 3],[2, 3]
Thanks.
Short answer is:
[[1, 1, 4], [2],[2, 3]].combination(2).flat_map {|x,y| x.product(y)}.uniq
# => [[1, 2], [4, 2], [1, 3], [4, 3], [2, 2], [2, 3]]
Step by step
step1 = [[1, 1, 4], [2],[2, 3]].combination(2)
# => [[[1, 1, 4], [2]], [[1, 1, 4], [2, 3]], [[2], [2, 3]]]
step2 = step1.flat_map {|x,y| x.product(y)}
# => [[1, 2], [1, 2], [4, 2], [1, 2], [1, 3], [1, 2], [1, 3], [4, 2], [4, 3], [2, 2], [2, 3]]
result = step2.uniq
# => [[1, 2], [4, 2], [1, 3], [4, 3], [2, 2], [2, 3]]
Update
For full uniqueness you could use:
[[1, 1, 4], [2],[2, 3, 4]].combination(2).flat_map {|x,y| x.product(y)}.map(&:sort).uniq
arr = [[1, 1, 4], [2], [2, 3]]
a = arr.map(&:uniq)
(arr.size-1).times.flat_map { |i| arr[i].product(arr[i+1..-1].flatten.uniq)}.uniq
#=> [[1,2],[1,3],[4,2],[4,3],[2,2],[2,3]]
Here's another way that uses the method Array#difference that I defined here:
arr.flatten.combination(2).to_a.difference(arr.flat_map { |a| a.combination(2).to_a }).uniq
Array#difference is similar to Array#-. The difference is illustrated in the following example:
a = [1,2,3,4,3,2,2,4]
b = [2,3,4,4,4]
a - b #=> [1]
a.difference b #=> [1, 3, 2, 2]

Resources