ruby array subrange when that range is a variable - arrays

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]

Related

Can someone explain in detail how mapping this array works step by step

The original array: [ [3, 5], [9, 6], [3,1] ]
1) Make the first number in each mini array the smaller number and the second number in each mini array the bigger number
- [ [3, 5], [9, 6], [3,1] ] -> [[ 3,5], [6,9], [1,3]]
2) Sort the mini arrays by first number.
- [ [3,5], [6,9], [1,3] ] -> [ [1,3], [3,5], [6,9] ]
So [ [3, 5], [9, 6], [3,1] ] -> [ [1,3], [3,5], [6,9] ] by the end of the sorting transformation.
Can someone explain in a step by step, detailed, clear, concise way how to use array.map() to make this happen?
Use map to make the nested array numbers placed in increasing order, then apply sort based on first number in the nested array.
const arr = [
[3, 5],
[9, 6],
[3, 1]
];
const sortedArr = arr
.map(([num1, num2]) => num2 < num1 ? [num2, num1] : [num1, num2])
.sort(([arr1num1], [arr2num1]) => arr1num1 - arr2num1);
console.log(sortedArr);
-- Edit--
Result of map
[[3, 5], [6, 9], [1, 3]];
In the sort function, I'am doing array destructuring (see - https://javascript.info/destructuring-assignment). Basically, I'am only extracting the first element from array and storing in separate variable. In our case, arr1num1 and arr2num1.
Example-
const arr = [3, 5];
// Extracting the first element from array and saving in variable - arr1num1.
// I do not need second array element 5, so i did not extracted the second array element
const [arr1num1] = arr; // arr1num1 will have now value 3
console.log(arr1num1);
// If second array element is also required, then the above statement will become const [num1, num2] = arr; where num1 -> 3 and num2 ->5
Alternative, to above would be to directly access array elements using there index.
const arr = [
[3, 5],
[9, 6],
[3, 1]
];
const sortedArr = arr
.map(([num1, num2]) => num2 < num1 ? [num2, num1] : [num1, num2])
.sort((arr1, arr2) => arr1[0] - arr2[0]);
console.log(sortedArr);
To know more about sort, see - Sorting
How sorting works,
In first iteration, swapping of [3, 5] & [6, 9] will happen based on sort condition.
arr1num1 -> 3
arr2num1 -> 6
The statement arr1num1 - arr2num1 will check if 3 is greater than 6. If yes, it will swap the arrays [3, 5] and [6, 9]. Since, 3 is not greater than 9, so no swapping will take place.
Second Iteration, swapping of [6, 9] and [1, 3] will take place based on condition.
arr1num1 -> 6
arr1num2 -> 1
Since, 6 > than 1, swapping will take place.
Before Swapping array will be- `[[3, 5], [6, 9], [1, 3]]`;
After Swapping array will be - `[[3, 5], [1, 3], [6, 9]]`;
This process will continue, until your array gets sorted.

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.

Am I misunderstanding 'min'?

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]

Unintuitive behaviour of array.map

So this behaviour seems to be logical
> array = (1..4).to_a
=> [1, 2, 3, 4]
> array.map {|a| [array.delete(array.first), array.delete(array.last)]}
=> [[1, 4], [2, 3]]
> array
=> []
But then when we increase the range it doesn't work:
> array = (1..6).to_a
=> [1, 2, 3, 4, 5, 6]
> array.map {|a| [array.delete(array.first), array.delete(array.last)]}
=> [[1, 6], [2, 5]]
> array
=> [3, 4]
And it does the same weird behaviour with odd numbers:
> array = (1..9).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
> array.map {|a| [array.delete(array.first), array.delete(array.last)]}
=> [[1, 9], [2, 8], [3, 7]]
> array
=> [4, 5, 6]
This was not what we expected, why does it behave this way?
This is a guess since I am not sure if this is the exact case but I can't put this as a comment.
So lets go step by step:
you defined an array:
> array = (1..6).to_a
=> [1, 2, 3, 4, 5, 6]
Now defined an iterator:
array.map {|a| [array.delete(array.first), array.delete(array.last)]}
so for first iteration it will take array[0] as the value for for variable a and do the operation and hence deleting first and last element of the array.
After first iteration array becomes [2,3,4,5].
For second iteration it will take array[1] as the value for for variable a and do the same as in first iteration and delete first and last element. Now array is [3,4].
Now for 3rd iteration, well it would not have tried for 3rd iteration if your original array was only size of 2 i.e like [2,3] but since you modified your original array during iteration so it will attempt 3rd iteration since original array had length 6.
For 3rd iteration it needs array's third element i.e array[2] but your current array does not have that index so it returns the remaining array without any other operation.
It is really confusing to modify array while being iterated.

Combine arrays in Ruby

I have two arrays as in the listing given below.
a = [1, 2, 3, 4, 5]
b = [1.360, 0.085, -1.190, -0.340, 3.698]
I need to merge the values at each index so that I get a structure resembling Resultant Array.
Resultant Array = [[1, 1.360], [2, 0.085], [3, -1.190], [4, -0.340], [5, 3.698]]
How do I go about doing it?
You can use Array#zip
a.zip(b)
# => [[1, 1.36], [2, 0.085], [3, -1.19], [4, -0.34], [5, 3.698]]
a = [1, 2, 3, 4, 5]
b = [1.360, 0.085, -1.190, -0.340, 3.698]
You can also try an alternative:
[a,b].transpose
Note: Use this when length of your array is same
You can do:
a.zip(b) #=> [[1,1.360],[2,0.085],[3,-1.190],[4,-0.340],[5,3.698]]
I didn't try it.
Source: apidoc.com

Resources