How to iterate an array every 30 items - ruby

I have an array of products with 234 items.
I need to create another array with a pagination (every 10 items)
example:
[
[1,2,3,4,5,6,7,8,9,10],
[1,2,3,4,5,6,7,8,9,10],
[1,2,3,4,5,6,7,8,9,10],
...
]
How can I solve this?
I've tried in_groups_of but I don't have success.

You're looking for each_slice
Whenever you have an array problem, check the Enumerable. in_groups_of is a Rails method and uses each_slice under the hood.

Just use Enumerable#each_slice
[*1..34].each_slice(10).to_a
# =>
# [
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
# [11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
# [21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
# [31, 32, 33, 34]
# ]

Related

split an array which comtains partially relatively order into two sorted array in O(n) time

Assume I have two arrays, both of them are sorted, for example:
A: [1, 4, 5, 8, 10, 24]
B: [3, 6, 9, 29, 50, 65]
And then I merge these two array into one array and keep original relative order of both two array
C: [1, 4, 3, 5, 6, 9, 8, 29, 10, 24, 50, 65]
Is there any way to split C into two sorted array in O(n) time?
note: not necessarily into the original A and B
Greedily assign your integers to list 1 if they can go there. If they can't, assign them to list 2.
Here's some Ruby code to play around with this idea. It randomly splits the integers from 0 to n-1 into two sorted lists, then randomly merges them, then applies the greedy approach.
def f(n)
split1 = []
split2 = []
0.upto(n-1) do |i|
if rand < 0.5
split1.append(i)
else
split2.append(i)
end
end
puts "input 1: #{split1.to_s}"
puts "input 2: #{split2.to_s}"
merged = []
split1.reverse!
split2.reverse!
while split1.length > 0 && split2.length > 0
if rand < 0.5
merged.append(split1.pop)
else
merged.append(split2.pop)
end
end
merged += split1.reverse
merged += split2.reverse
puts "merged: #{merged.to_s}"
merged.reverse!
greedy1 = [merged.pop]
greedy2 = []
while merged.length > 0
if merged[-1] >= greedy1[-1]
greedy1.append(merged.pop)
else
greedy2.append(merged.pop)
end
end
puts "greedy1: #{greedy1.to_s}"
puts "greedy2: #{greedy2.to_s}"
end
Here's sample output:
> f(20)
input 1: [2, 3, 4, 5, 8, 9, 10, 18, 19]
input 2: [0, 1, 6, 7, 11, 12, 13, 14, 15, 16, 17]
merged: [2, 0, 1, 6, 3, 4, 5, 8, 9, 7, 10, 11, 18, 12, 13, 19, 14, 15, 16, 17]
greedy1: [2, 6, 8, 9, 10, 11, 18, 19]
greedy2: [0, 1, 3, 4, 5, 7, 12, 13, 14, 15, 16, 17]
> f(20)
input 1: [1, 3, 5, 6, 8, 9, 10, 11, 13, 15]
input 2: [0, 2, 4, 7, 12, 14, 16, 17, 18, 19]
merged: [0, 2, 4, 7, 12, 14, 16, 1, 3, 5, 6, 8, 17, 9, 18, 10, 19, 11, 13, 15]
greedy1: [0, 2, 4, 7, 12, 14, 16, 17, 18, 19]
greedy2: [1, 3, 5, 6, 8, 9, 10, 11, 13, 15]
> f(20)
input 1: [0, 1, 2, 6, 7, 9, 11, 14, 15, 18]
input 2: [3, 4, 5, 8, 10, 12, 13, 16, 17, 19]
merged: [3, 4, 5, 8, 10, 12, 0, 13, 16, 17, 1, 19, 2, 6, 7, 9, 11, 14, 15, 18]
greedy1: [3, 4, 5, 8, 10, 12, 13, 16, 17, 19]
greedy2: [0, 1, 2, 6, 7, 9, 11, 14, 15, 18]
Let's take your example.
[1, 4, 3, 5, 6, 9, 8, 29, 10, 24, 50, 65]
In time O(n) you can work out the minimum of the tail.
[1, 3, 3, 5, 6, 8, 8, 10, 10, 24, 50, 65]
And now the one stream is all cases where it is the minimum, and the other is the cases where it isn't.
[1, 3, 5, 6, 8, 10, 24, 50, 65]
[ 4, 9, 29, ]
This is all doable in time O(n).
We can go further and now split into 3 streams based on which values in the first stream could have gone in the last without changing it being increasing.
[ 3, 5, 6, 8, 10, 24, ]
[1, 5, 6, 8, 50, 65]
[ 4, 9, 29, ]
And now we can start enumerating the 2^6 = 64 different ways of splitting the original stream back into 2 increasing streams.

multiplication table in Ruby

Can you please help me?
I'm solving an exercise in Ruby and the result has to be like this:
it 'multiplication table de 1 a 10' do
expect(ArrayUtils.tabuada(10)).to eq [
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20],
[3, 6, 9, 12, 15, 18, 21, 24, 27, 30],
[4, 8, 12, 16, 20, 24, 28, 32, 36, 40],
[5, 10, 15, 20, 25, 30, 35, 40, 45, 50],
[6, 12, 18, 24, 30, 36, 42, 48, 54, 60],
[7, 14, 21, 28, 35, 42, 49, 56, 63, 70],
[8, 16, 24, 32, 40, 48, 56, 64, 72, 80],
[9, 18, 27, 36, 45, 54, 63, 72, 81, 90],
[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
]
end
it 'multiplication table de 1 a 3' do
expect(ArrayUtils.tabuada(3)).to eq [
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20],
[3, 6, 9, 12, 15, 18, 21, 24, 27, 30],
]
end
My code:
def self.tabuada(n)
(1..n).each do |element|
(1..n-1).each { |item| print "#{element * item}, " }
puts element * n
end
end
tabuada(3)
It's the result:
1, 2, 3
2, 4, 6
3, 6, 9
Any suggestion?
There are two issues in your code:
The test expects you to return a nested array, not to print the result
The inner loop always ends a 10, it is not depending on the n at all
I would start with something like this:
def self.tabuada(n)
(1..n).map do |n|
(1..10).map do |i|
n * i
end
end
end
Or:
def self.tabuada(n)
(1..n).map { |element| Array.new(10) { |i| (i + 1) * element } }
end
Good error messages are very important for a good testing framework.
The error messages should guide you to a solution.
It looks like you are using RSpec, which does indeed have good error messages. So, let's just look at the error message we get:
expected: [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [2, 4, 6, 8, 10, 12, 14, 16, 18, 20], [3, 6, 9, 12, 15, 18, 21, 24,...56, 64, 72, 80], [9, 18, 27, 36, 45, 54, 63, 72, 81, 90], [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]]
got: 1..10
(compared using ==)
So, the error message is telling us that RSpec expected to find an array, but instead your method returned a range. That's interesting, so let's look at what does your method return.
Well, in the absence of an explicit return keyword, a method definition body evaluates to the value of the last expression that was evaluated inside the method definition body. In your case, there is only a single expression inside the method, so the value of that expression is returned:
(1..n).each do |element|
(1..n-1).each { |item| print "#{element * item}, " }
puts element * n
end
What is the return value of (1..n).each? We can simply look at the documentation, and we see that Range#each returns self, i.e. the object that it was called on. So, the return value of your method will always be simply the range 1..n, and not the array of arrays that the test expects.
[Sidenote: I did, in fact, not look up what Range#each returns. Every implementation of each for every collection always returns self, that is part of the contract of each. This is one of the things you just learn over time when you program in Ruby.]
Let's do the simplest possible thing we can do to change the message. That is all we want to do. We don't want to fix everything and we don't want to take a huge step. We just want to make a tiny change that changes the error message.
If we look at the methods available to us, we find the method Enumerable#map, which transforms the elements and returns an array of the transformed elements. That actually sounds quite good, since transforming some numbers into a table of multiplied numbers is pretty much exactly what we want to do.
So, we just change the each to map. Nothing more:
(1..n).map do |element|
(1..n-1).each { |item| print "#{element * item}, " }
puts element * n
end
And then we see what happens:
got: [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]
That is already better. We are expecting an array, and we are getting an array. Just the wrong array, but we already have the correct type! Before, we were getting a range, now we are getting an array.
Why is this array filled with nils, though? We want numbers! If we look at the documentation of map again, we see that the value of the block is used to fill the array. So, what is the value of the block?
Just as above, the value of the whole block is the value of the last expression evaluated inside the block. The last expression inside the block is
puts element * n
And if we look at the documentation of Kernel#puts, we can see that it does, indeed, return nil! But we want a number instead. Well, we already have a number: element * n is a number! So, instead of printing the number (which the problem description never asked for in the first place) and returning nil, let's just return the number. In other words, just remove the puts:
(1..n).map do |element|
(1..n-1).each { |item| print "#{element * item}, " }
element * n
end
And this is the result:
got: [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
Again, one step closer. We want an array, we have an array. We want numbers, we have numbers. What we actually want, though is not an array of numbers, but an array-of-arrays-of-numbers. If you look closely, you can see that we have here is actually the last array of the array-of-arrays-of-numbers we are expecting (or to put it another way, it is the last row of the table).
Hey, but we already know something that can produce arrays: map can do that! Turning the outer each into a map gave us an array. Naturally, nesting a map within a map will give us nested arrays. So, let's just do that:
(1..n).map do |element|
(1..n-1).map { |item| print "#{element * item}, " }
element * n
end
Hmm … actually, that didn't change anything. It makes sense, really: the value of the block is the value of the last expression, and the last expression is element * n. The map before it does return an array, but we're not doing anything with that array, we are just throwing it away.
So, let's just as an experiment remove the element * n and see what happens:
got: [[nil, nil, nil, nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil, nil, nil, nil], [nil, ... nil], [nil, nil, nil, nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil, nil, nil, nil]]
One step forward, one step back, I guess. We wanted an array-of-arrays-of-numbers, originally we had an array-of-numbers and were missing the "nesting" part, now we have a nested array-of-arrays, but we lost the numbers.
But we already know the cause, since we figured it out once before: Kernel#print returns nil, so let's just delete it:
(1..n).map do |element|
(1..n-1).map { |item| "#{element * item}, " }
end
And this is the result:
expected: [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [2, 4, 6, 8, 10, 12, 14, 16, 18, 20], [3, 6, 9, 12, 15, 18, 21, 24,...56, 64, 72, 80], [9, 18, 27, 36, 45, 54, 63, 72, 81, 90], [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]]
got: [["1, ", "2, ", "3, ", "4, ", "5, ", "6, ", "7, ", "8, ", "9, "], ["2, ", "4, ", "6, ", "8, ", "10, "..., "63, ", "72, ", "81, "], ["10, ", "20, ", "30, ", "40, ", "50, ", "60, ", "70, ", "80, ", "90, "]]
Hey, that's actually pretty close! We want an array-of-arrays-of-numbers, and we have an array-of-arrays-of-strings-with-numbers-in-them. Let's see what happens when we remove the string and simply keep the number:
(1..n).map do |element|
(1..n-1).map { |item| element * item }
end
expected: [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [2, 4, 6, 8, 10, 12, 14, 16, 18, 20], [3, 6, 9, 12, 15, 18, 21, 24,...56, 64, 72, 80], [9, 18, 27, 36, 45, 54, 63, 72, 81, 90], [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]]
got: [[1, 2, 3, 4, 5, 6, 7, 8, 9], [2, 4, 6, 8, 10, 12, 14, 16, 18], [3, 6, 9, 12, 15, 18, 21, 24, 27], [4... 32, 40, 48, 56, 64, 72], [9, 18, 27, 36, 45, 54, 63, 72, 81], [10, 20, 30, 40, 50, 60, 70, 80, 90]]
Cool! We are only counting one too low. That is because we were originally having a special case for the last number, and we simply removed that special case. As we can see now, there is actually no reason for the special case, so we can just incorporate the last number into our normal flow of the code:
(1..n).map do |element|
(1..n).map { |item| element * item }
end
Congratulations! The first of the two tests passes! We only have the second test to worry about now, which gives this error:
expected: [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [2, 4, 6, 8, 10, 12, 14, 16, 18, 20], [3, 6, 9, 12, 15, 18, 21, 24, 27, 30]]
got: [[1, 2, 3], [2, 4, 6], [3, 6, 9]]
Oh, I see what is going on here. In the first test, the multiplication table just happened to be square, so we implemented a square multiplication table. But actually, the rows are always supposed to be 10 columns wide, regardless of n, whereas we just assumed they were n wide because in the first test, n happened to be 10.
But that is easy to fix:
(1..n).map do |element|
(1..10).map { |item| element * item }
end
And now all of the tests pass!
You will notice that we get almost no output now. That is a standard programming philosophy: if everything is going well, do not print anything. Only print something when there is something wrong. If you print too much when things are going right, it will be hard to spot when something is going wrong. Also, you de-sensitize your users and they just start ignoring what is printed, because it isn't interesting to them.
That's why RSpec by default only prints a single green dot for every test that passes, and a single line summary at the end, and only prints large messages when things are going wrong:
..
Finished in 0.00701 seconds (files took 0.15231 seconds to load)
2 examples, 0 failures
There are, of course, many other ways to write this. What I wanted to show you, is how you could fix what you already had written, by doing nothing but blindly following RSpec's excellent error messages, and simply doing tiny little steps to change the error message into something different. You are not even trying to fix the error, you are only trying to change the error to something that is closer to your goal.
We didn't really have to think hard. The errors were pretty much telling us what to do. That is the hallmark of good error messages and good tests.
You can even do this when you have no code at all! There is a methodology called "Test-Driven Development" (TDD), which is centered around the idea that you write tests before you ever write the first line of code, and then develop your code by simply "listening to the errors".
In this case, it could look a little like this. We start with an empty file, and we get this error:
NameError:
uninitialized constant ArrayUtils
Remember, we are only trying to do the "simplest possible thing to change the error message". The error message says that the ArrayUtils constant is not initialized, so we just initialize it, nothing more:
ArrayUtils = nil
NoMethodError:
undefined method `tabuada' for nil:NilClass
Okay, now it is telling us that NilClass doesn't have a method called tabuada. All we do is the stupidest thing to change the error message: we add that method to NilClass:
class NilClass
def tabuada
end
end
Is this stupid? Yes, of course it is! But we're not trying to be clever here. We are, in fact, very much trying to be not clever. Debugging code is hard, harder than to write code. Which means that if you make your code as clever as you can, you are by definition not clever enough to debug it! So, let's stick with this for now.
ArgumentError:
wrong number of arguments (given 1, expected 0)
Okay, so let's just give it one:
def tabuada(_)
end
Now, we no longer get errors from Ruby but instead test failures from RSpec. That is already a good step:
expected: [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [2, 4, 6, 8, 10, 12, 14, 16, 18, 20], [3, 6, 9, 12, 15, 18, 21, 24,...56, 64, 72, 80], [9, 18, 27, 36, 45, 54, 63, 72, 81, 90], [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]]
got: nil
So, we're returning the wrong thing. We can easily fix that by returning what the test asks us to:
def tabuada(_)
[
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20],
[3, 6, 9, 12, 15, 18, 21, 24, 27, 30],
[4, 8, 12, 16, 20, 24, 28, 32, 36, 40],
[5, 10, 15, 20, 25, 30, 35, 40, 45, 50],
[6, 12, 18, 24, 30, 36, 42, 48, 54, 60],
[7, 14, 21, 28, 35, 42, 49, 56, 63, 70],
[8, 16, 24, 32, 40, 48, 56, 64, 72, 80],
[9, 18, 27, 36, 45, 54, 63, 72, 81, 90],
[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
]
end
This passes the first test, obviously, but not the second. Now, we could add a conditional expression like this:
def tabuada(_)
if _ == 10
[
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20],
[3, 6, 9, 12, 15, 18, 21, 24, 27, 30],
[4, 8, 12, 16, 20, 24, 28, 32, 36, 40],
[5, 10, 15, 20, 25, 30, 35, 40, 45, 50],
[6, 12, 18, 24, 30, 36, 42, 48, 54, 60],
[7, 14, 21, 28, 35, 42, 49, 56, 63, 70],
[8, 16, 24, 32, 40, 48, 56, 64, 72, 80],
[9, 18, 27, 36, 45, 54, 63, 72, 81, 90],
[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
]
else
[
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20],
[3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
]
end
end
However, it should be clear that this is not the spirit of the problem. If there were more tests, we would have to add a new clause for every number. In particular, this should be working for infinitely many numbers.
So, we'll have rethink our approach. Let's go back. All we need is an array, so let's start with an array:
def tabuada(_)
[]
end
As a first step, our array needs to have as many rows as the argument. If you want to create an array with a certain number of elements, you can use Array::new:
def tabuada(_)
Array.new(_)
end
got: [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]
The length is good. But the contents are not. The contents should also be an array:
def tabuada(_)
Array.new(_) { Array.new(10) }
end
got: [[nil, nil, nil, nil, nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil, nil, nil, nil, ni...l, nil, nil, nil, nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]]
That's great, the result array already has the shape we want, now it's just missing the content. Array::new yields the index to the block, so we can use that to create the content:
def tabuada(_)
Array.new(_) { |a| Array.new(10) { |b| a * b }}
end
got: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 2, 4, 6, 8, 10, 12, 14, 16, 18],...35, 42, 49, 56, 63], [0, 8, 16, 24, 32, 40, 48, 56, 64, 72], [0, 9, 18, 27, 36, 45, 54, 63, 72, 81]]
We are very close now! As I said above, Array::new yields the index, but Ruby array indices range from 0 to size-1, not 1 to size, so all that is left to do is add 1 to the index, or alternatively, use the successor:
def tabuada(_)
Array.new(_) { |a| Array.new(10) { |b| a.succ * b.succ }}
end
And now, all of our tests pass!
Now that we have passing tests comes a very important step: Refactoring. Refactoring means:
While the tests are passing,
in small, well-defined, reversible steps,
change the structure of the code without changing its behavior
to make it look like you had the whole design figured out from the beginning.
Our first refactoring is going to be the Rename Parameter Refactoring. When we introduced the parameter, we were ignoring it, so we gave it the standard name for an ignored parameter: _. But that is a terrible name, so we will rename it to n:
def tabuada(n)
Array.new(n) { |a| Array.new(10) { |b| a.succ * b.succ }}
end
And we run our tests again to make sure that we haven't broken anything.
Our next refactoring is going to be the Move Method Refactoring. We very stupidly followed the error message telling us that it couldn't find the method tabuada on nil, so we did the simplest possible thing and added tabuada to nil. But, that doesn't make much sense.
Instead, we want to add it to ArrayUtils, which at that point just happened to be nil.
Which means that first, we need to change ArrayUtils to something else. Most Ruby programmers would probably use a module, but for something that is not going to be mixed and only used as a container for singleton methods, I personally actually prefer an empty BasicObject. So, let's do that and then move the method to it:
ArrayUtils = BasicObject.new
def ArrayUtils.tabuada(n)
Array.new(n) {|a| Array.new(10) {|b| a.succ * b.succ } }
end
We can slightly shorten this to something like this:
def (ArrayUtils = BasicObject.new).tabuada(n)
Array.new(n) {|a| Array.new(10) {|b| a.succ * b.succ } }
end
Note that in both cases, in the first example where we started from your failing code and fixed it, and in the second example where we started from an empty file, we always worked in small simple steps:
Read the error message.
Understand the error.
Make the simples, smallest, stupidest change to the code to change just one aspect of the error message.
Read the new error message.
Understand the error.
Check that the new error is a step forward or at least sideward.
If not, revert the change and try something different.
Else, go to #3 and repeat until the tests pass.
Only when the tests pass: refactor to make it look as if we had known where we are going from the beginning.
The tests ensure that we are always moving forward. The small steps ensure that we always understand what we are doing, and when things go wrong, we know the problem can only be in the tiny piece of code we changed. They also ensure that when we have to revert, we are only losing a couple seconds worth of work.

Remove n elements from array dynamically and add to another array

nums= [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
new_array=[]
How do I grab every two items divisible by 5 and add them to a new array.
This is the desired result:
the new_array should now contain these values
[[5,10],[15,20],[25,30]]
Note: I want to do this without pushing them all into the array and then performing
array.each_slice(2). The process should happen dynamically.
Try this
new_array = nums.select { |x| x % 5 == 0 }.each_slice(2).entries
No push involved.

How to split a range into N parts

I am wondering how to split a range into N parts in ruby, While adding them to a hash with a zero based value for each range generated.
For example:
range = 1..60
p split(range, 4)
#=> {1..15 => 0, 16..30 => 1, 31..45 => 2, 46..60 => 3}
I've read How to return a part of an array in Ruby? for how to slice a range into an array, and a few others on how to convert the slices back into ranges, but I can't quite seem to piece all the pieces together to create the method I want.
Thanks for the help
range = 1..60
range.each_slice(range.last/4).with_index.with_object({}) { |(a,i),h|
h[a.first..a.last]=i }
#=> {1..15=>0, 16..30=>1, 31..45=>2, 46..60=>3}
The steps are as follows:
enum0 = range.each_slice(range.last/4)
#=> range.each_slice(60/4)
# #<Enumerator: 1..60:each_slice(15)>
You can convert this enumerator to an array to see the (4) elements it will generate and pass to each_with_index:
enum0.to_a
#=> [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
# [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
# [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45],
# [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60]]
enum1 = enum0.with_index
#=> #<Enumerator: #<Enumerator: 1..60:each_slice(15)>:with_index>
enum1.to_a
#=> [[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], 0],
# [[16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30], 1],
# [[31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], 2],
# [[46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60], 3]]
enum2 = enum1.with_object({})
#=> #<Enumerator: #<Enumerator: #<Enumerator: 1..60:each_slice(15)>
# :with_index>:with_object({})>
enum2.to_a
#=> [[[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], 0], {}],
# [[[16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30], 1], {}],
# [[[31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], 2], {}],
# [[[46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60], 3], {}]]
Carefully examine the return values for the calculations of enum1 and enum2. You might want to think of them as "compound" enumerators. The second and last element of each of enum2's four arrays is the empty hash that is represented by the block variable h. That hash will be constructed in subsequent calculations.
enum2.each { |(a,i),h| h[a.first..a.last]=i }
#=> {1..15=>0, 16..30=>1, 31..45=>2, 46..60=>3}
The first element of enum2 that is passed by each to the block (before enum.each... is executed) is
arr = enum2.next
#=>[[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], 0], {}]
The block variables are assigned to the elements of arr using parallel assignment (sometimes called multiple assignment)
(a,i),h = arr
#=> [[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], 0], {}]
a #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
i #=> 0
h #=> {}
The block calculation is therefore
h[a.first..a.last]=i
#=> h[1..15] = 0
Now
h #=> {1..15=>0}
The calculations are similar for each of the other 3 elements generated by enum2.
The expression
enum2.each { |(a,i),h| h[(a.first..a.last)]=i }
could alternatively be written
enum2.each { |((f,*_,l),i),h| h[(f..l)]=i }

How to remove outer array from a nested array?

If I have the following arr = [13,12,31,31] Now say I want to push in another set of numbers like 12,13,54,32
So I can do arr << [12,13,54,32] but now I have [13,12,31,31,[12,13,54,32]]
So how can I remove the outside array? arr = arr.pop works sometimes but I'm guessing that a better way exists. Please enlighten.
Don't use <<, use +
arr = [13,12,31,31]
arr += [12,13,54,32]
# arr => [13,12,31,31,12,13,54,32]
You should use Array#flatten
[[13,12,31,31,12,13,54,32]].flatten # => [13, 12, 31, 31, 12, 13, 54, 32]
You have a couple options. You could join your arrays using the + operator and not have to deal with the outer array. If you have an outer array and want to flatten it, simply call flatten on the array. As matt mentioned in the comments above, you can also use concat.
# Creates a new array
[13,12,31,31] + [12,13,54,32]
=> [13, 12, 31, 31, 12, 13, 54, 32]
# Creates a new array, unless you use flatten!
[13, 12, 31, 31, [12, 13, 54, 32]].flatten
=> [13, 12, 31, 31, 12, 13, 54, 32]
# Modifies the original array
[13,12,31,31].concat([12,13,54,32])
=> [13, 12, 31, 31, 12, 13, 54, 32]

Resources