Am I misunderstanding 'min'? - arrays

I have:
array1 = [[0, 0], [2, 1]]
array2 = [[1, 0], [3, 1]]
I believe this should be the case:
array1[1][0] == [0, 2]
array2[1][0] == [0, 3]
Following this, why is it that the following code,
[array1[1][0], array2[1][0]].min # => 2
returns 2?
How is it that 2 is the minimum out of two-dimensional arrays in which there are three instances of 0 and three instances of 1?
Am I misunderstanding the min function, or am I misunderstanding what is going on when I use the two-dimensional arrays?

When [1][0] call for the first array you take the second array from it [2, 1] and then take the first number from taken array 2.
array1[1][0] => 2
array2[1][0] => 3
[2, 3].min => 2

It goes like:
array1[1][0] == [2, 1][0] == 2
array2[1][0] == [3, 1][0] == 3
[array1[1][0], array2[1][0]].min == [2, 3].min # => 2
Under your counterfactual assumption:
array1[1][0] == [0, 2]
array2[1][0] == [0, 3]
the comparison should be:
[array1[1][0], array2[1][0]].min == [[0, 2], [0, 3]].min # => [0, 2]

Related

create matrix from coordinate (x, y) ruby

I can get positions of a Matrix with this code:
rows = 2
columns = 2
Matrix.build(rows, columns).to_a
[[0, 0], [0, 1], [1, 0], [1, 1]]
this code is building a matrix from 0,0.
I would like build a matrix from 0,1
i would like to get:
[[0, 1], [0, 2], [1, 1], [1, 2]]
i'm using build matrix method, because is easy, we can use arrays to achieve the same result.
Thanks!
Given
rows = 2
columns = 2
offset = [0, 1]
simply write
ro, co = offset
Array.new(rows * columns) do |k|
i, j = k.divmod(rows)
[i + ro, j + co]
end
#=> [[0, 1], [0, 2], [1, 1], [1, 2]]
See Array::new and Integer#divmod.

How to create a mask for nd values in a 2d NumPy array?

If I want to create a mask depending on a 1d value in a 2d array:
a = np.array([[3, 5], [7, 1]])
threshold = 2
mask = a > threshold
print(a)
print(mask)
I get:
[[3 5]
[7 2]]
[[ True True]
[ True False]]
How can I create such a mask for a 2d array with nd values? Like the following example of 2d values and a 2d threshold in a 2d array:
b = np.array([[[1, 5], [3, 5]], [[4, 4], [7, 2]]])
threshold = 2, 4
print(b)
Looks like this:
[[[1 5]
[3 5]]
[[4 4]
[7 2]]]
[1, 5], [3, 5], [4, 4] and [7, 2] are the exemplary 2d values. The threshold, as set in threshold, for the first value is 2 and for the second value it's 4:
cell for [1, 5] should be False since 1 > 2 == False and 5 > 4 == True
cell for [3, 5] should be True since 3 > 2 == True and 5 > 4 == True
cell for [4, 4] should be False since 4 > 2 == True and 4 > 4 == False
cell for [7, 2] should be False since 7 > 2 == True and 2 > 4 == False
What do I have to do to get this corresponding mask?
[[ False True]
[ False False]]
numpy broadcasted comparison actually handles this quite nicely for you. Just make your threshold a 1D array and assert all along the final axis.
t = np.array([2, 4])
(b > t).all(-1)
array([[False, True],
[False, False]])
To clarify however, your array is actually 3D. If your array was 2D, like below, this would work a bit differently:
arr = np.array([[1, 5],
[3, 5],
[4, 4],
[7, 2]])
(arr > t).all(-1)
array([False, True, False, False])

How to find indices of max n elements in array in stable order

I have a number and an array:
n = 4
a = [0, 1, 2, 3, 3, 4]
I want to find the indices corresponding to the maximal n elements of a in the reverse order of the element size, and in stable order when the element sizes are equal. The expected output is:
[5, 3, 4, 2]
This code:
a.each_with_index.max(n).map(&:last)
# => [5, 4, 3, 2]
gives the right indices, but changes the order.
Code
def max_with_order(arr, n)
arr.each_with_index.max_by(n) { |x,i| [x,-i] }.map(&:last)
end
Examples
a = [0,1,2,3,3,4]
max_with_order(a, 1) #=> [5]
max_with_order(a, 2) #=> [5, 3]
max_with_order(a, 3) #=> [5, 3, 4]
max_with_order(a, 4) #=> [5, 3, 4, 2]
max_with_order(a, 5) #=> [5, 3, 4, 2, 1]
max_with_order(a, 6) #=> [5, 3, 4, 2, 1, 0]
Explanation
For n = 3 the steps are as follows.
b = a.each_with_index
#=> #<Enumerator: [0, 1, 2, 3, 3, 4]:each_with_index>
We can convert b to an array to see the (six) values it will generate and pass to the block.
b.to_a
#=> [[0, 0], [1, 1], [2, 2], [3, 3], [3, 4], [4, 5]]
Continuing,
c = b.max_by(n) { |x,i| [x,-i] }
#=> [[4, 5], [3, 3], [3, 4]]
c.map(&:last)
#=> [5, 3, 4]
Note that the elements of arr need not be numeric, merely comparable.
You can supply a block to max to make the determination more specific like so
a.each_with_index.max(n) do |a,b|
if a[0] == b[0] # the numbers are the same
b[1] <=> a[1] # compare the indexes in reverse
else
a[0] <=> b[0] # compare the numbers themselves
end
end.map(&:last)
#=> [5,3,4,2]
max block expects a comparable response e.g. -1,0,1 so in this case we are just saying if the number is the same then compare the indexes in reverse order e.g. 4 <=> 3 #=> -1 the -1 indicates this values is less so that will then be placed after 3
Also to expand on #CarySwoveland's answer (which I am a bit jealous I did not think of), since you only care about returning the indices we could implement as follows without a secondary map
a.each_index.max_by(n) { |x| [a[x],-x] }
#=> [5,3,4,2]
#compsy you wrote without changing order, so it would be:
a = [0,1,2,3,3,4]
n = a.max
i = 0
a.each do |x|
break if x == n
i += 1
end
I use variable i as index, when x (which is the value beeing analized) is equals n we use break to stop the each method conserving the last value of i wich corresponds to the position of the max value at the array. Be aware that value of i is different by one of the natural position in the array, and tht is because in arrays the first element is 0 not 1.
I break the each because there is no need to keep checking all the other values of the array after we found the position of the value.

Circular array slicing

I have an array with a varying number of elements 0..n elements. An example could be:
a = [0,1,2,3,4,5,6,7,8,9]
In an iterative process, I would like to move a cursor in the array and slice out a max number of elements. If I reach the "end" of the array, it should start over and pick from the beginning again:
Something like this:
4.times do |i|
a.slice(i * 3, 3)
end
# i = 0 => [0,1,2]
# i = 1 => [3,4,5]
# i = 2 => [6,7,8]
# i = 3 => [9,0,1]
# ...
However the last output i = 3 produces [9] as .slice does not do exactly what I want.
You could use cycle:
a.cycle.each_slice(3).take(4)
#=> [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 0, 1]]
You could use Array#rotate, and then take the first 3 elements each time:
4.times.each { |i| a.rotate(i*3)[0..2] }
# => [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 0, 1]]
Possible solution:
4.times { |i| p a.values_at(*(i*3..i*3+2).map {|e| e % 10 }) }
[0, 1, 2]
[3, 4, 5]
[6, 7, 8]
[9, 0, 1]
9%10 = 9, 10%10 = 0, 11%10 = 1. So you will get the desired output.
This might break some code, so be careful.
class Array
alias_method :old_slice, :slice
def slice(o, c)
ret = old_slice(o % size, c)
if ret.size != c
ret += old_slice(0, c - ret.size)
end
ret
end
end
a = [0,1,2,3,4,5,6,7,8,9]
4.times do |i|
p a.slice(i * 3, 3)
end
As Stephan points out it would be better to give this method a different name, or it might be even better to create a CircularArray class.
class CircularArray < Array
alias_method :straight_slice, :slice
def slice(o, c)
ret = straight_slice(o % size, c)
if ret.size != c
ret += straight_slice(0, c - ret.size)
end
ret
end
end

ruby array subrange when that range is a variable

Is it possible to apply a sub range to an array in ruby like this:
> array = [4, 3, 2, 1]
> array[0...2]
=> [4, 3]
if the [0...2] is stored in a variable? I can't seem to get a syntax to give me what I want. What replaces the <?> in the following, if anything?
> array = [4, 3, 2, 1]
> range = [0...2]
> array<?>
=> [4, 3]
Yes, sure! Do this way:
array = [4, 3, 2, 1]
exclusive_range = [0...2] # Will get 0th and 1st element of the array
inclusive_range = [0..2] # Will get 0th, 1st and 2nd element of the array
array[exclusive_range.first]
# => [4, 3]
array[inclusive_range.first]
# => [4, 3, 2]
If you want to avoid .first call, you can put your range in a variable (Not in an array):
range = 0...2
array[range]
# => [4, 3]
Note that (0..2).size #=> 3. If you want to return [4,3] you want:
range = 0..1
You could use it like this:
array[range] #=> [4, 3]
or like this:
array.values_at *range #=> [4, 3]

Resources