What's the reason the second code won't return what the first code successfully returns - ruby

I was doing a quick read up on arrays and some basic methods. And one of the exercise questions at the end of the reading gave me an array and asked to get the following output
=> [10, 8, 4, 2]
Here's the array:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
solution:1
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers = numbers.select { |number| number.even? }.reverse
numbers.delete(6)
p numbers
But my question to you is why would the above code return the correct output but the following code won't?
solution: 2
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers = numbers.select { |number| number.even? }
numbers.delete(6)
numbers.reverse
p numbers
I understand it's not the most fluent, but when I try to solve these exercises it's easier for me to separate everything and then clean up the code.
I expected it to pull the even numbers delete 6 from them and then print the reversed array.
Instead it pulls the even numbers, deletes 6, and prints the even numbers. Completely skips the .reverse

As max says, .reverse doesn't change the array. Try, instead:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers = numbers.select { |number| number.even? }
numbers.delete(6)
numbers.reverse!
p numbers
=> [10, 8, 4, 2]

As other commenters have mentioned, .reverse doesn't change the array.
You either have to declare numbers.reverse as a new variable (i.e. reversed_numbers = numbers.reverse) or use numbers.reverse! (as demonstrated by jvillian) to change the value of the numbers variable itself at invocation.
Between the two, the latter method is more suitable.
Hope this helped!

Related

How to merge arrays to one array kind of respectively in ruby

I want to combine the arrays together to add the first column of all arrays, then the second columns, respectively, to the end.
My arrays :
[1,2,3,4,5]
[6,7,8,9,10]
[11,12,13,14,15]
i want result :
[1,6,11 , 2,7,12 , 3,8,13 , 4,9,14 , 5,10,15]
Suppose we have a "simple" case where the three arrays are the same length:
a = [1,2,3,4,5]
b = [6,7,8,9,10]
c = [11,12,13,14,15]
In this case, you can use Array#zip to merge the arrays in your desired way, then flatten the result into a single array:
a.zip(b, c).flatten
#=> [1, 6, 11, 2, 7, 12, 3, 8, 13, 4, 9, 14, 5, 10, 15]
However, what if a.length > b.length or b.length > c.length?
a = [1,2,3,4,5]
b = [6,7,8,9]
c = [10,11,12]
This is a little bit harder, because now Array#zip will leave you with some nil values that you presumably want to remove:
a.zip(b, c).flatten
#=> [1, 6, 10, 2, 7, 11, 3, 8, 12, 4, 9, nil, 5, nil, nil]
a.zip(b, c).flatten.compact
#=> [1, 6, 10, 2, 7, 11, 3, 8, 12, 4, 9, 5]
And finally, what if a.length < b.length or b.length < c.length?
a = [1,2,3]
b = [4,5,6,7]
c = [8,9,10,11,12]
This is again a bit harder. Now, you'll presumably want to pad the arrays with as many nils as needed, and then perform the same operation as above:
max_length = [a,b,c].map(&:length).max
def padded_array(array, size)
array.dup.fill(nil, array.length, size)
end
padded_array(a, max_length).zip(
padded_array(b, max_length), padded_array(c, max_length)
).flatten.compact
So the complexity of your final answer depends on what arrays you are dealing with, and how far you need to go with accounting for edge cases.
a = [1,2,3,4,5]
b = [6,7,8,9,10]
c = [11,12,13,14,15]
((a.zip b).zip c).flatten.compact
=> [1, 6, 11, 2, 7, 12, 3, 8, 13, 4, 9, 14, 5, 10, 15]

Can I have a ruby block inside another ruby block?

I have a hash whose keys are a range of integers (lets say [1..5]) and its corresponding 5 values are all nil. I have also an array of integers (lets say [1,2,3,4,5]. What I want to do is very specific: I want to take every single key and add it to every single of the array elements, giving me a hash that has the original keys, but has now for values the entire shifted array.
After spending a few hours I have concluded that this is impossible through a really laconic expression, because it is leading to .each shadowing statements.
I think that the only way to go through with this is to create 5 almost identical methods and call them separately.
def a1
array.each do |x|
x+1
end
end
def a2
array.each do |x|
x+2
end
end
and so on..
The end product I want to achieve is this:
{1=>[2,3,4,5,6],2=>[3,4,5,6,7],3=>[4,5,6,7,8],4=>[5,6,7,8,9],5=>[6,7,8,9,10]}
It feels like there should be a more DRY way to achieve this. Any ideas?
Assuming these initial conditions:
h = {1=>nil, 2=>nil, 3=>nil, 4=>nil, 5=>nil}
arr = [1,2,3,4,5]
...it's pretty straightforward:
h.keys.each do |key|
h[key] = arr.map {|i| i+key}
end
# h is now: {1=>[2, 3, 4, 5, 6], 2=>[3, 4, 5, 6, 7], 3=>[4, 5, 6, 7, 8], 4=>[5, 6, 7, 8, 9], 5=>[6, 7, 8, 9, 10]}
(However, it may be that your question is about achieving the initial conditions. If so, I didn't grasp that, and I didn't worry about it; I just started with what I took to be your initial conditions and ended up with your desired result.)
Why don't you do this
h = {}
rng.each{|i| h[i] = ary.map{|j| j + i}}
That should work where rng is the range and ary is the array.
For example
h = {}
(1..5).each{|i| h[i] = [1,2,3,4,5].map{|j| j+i}}
results in
h = {1=>[2, 3, 4, 5, 6], 2=>[3, 4, 5, 6, 7], 3=>[4, 5, 6, 7, 8], 4=>[5, 6, 7, 8, 9], 5=>[6, 7, 8, 9, 10]}

Ruby code to merge two arrays not working

nums1 = Array[1, 2, 3, 4, 5]
nums2 = Array[5, 6, 7, 8, 9]
def mergeArrays (ar1, ar2)
result = (ar1 << ar2).flatten!
require 'pp'
pp %w(result)
end
As simple as this. I am trying to merge these two arrays and display the result. I am also brand-brand new to Ruby. This is the first function I am writing in this language. Trying to learn here. Also how can I remove the duplicates?
It would help if you give example inputs and outputs so we know exactly what you want. When you use the word "merge", I think you actually just want to add the arrays together:
ar1 = [1, 2, 3]
ar2 = [3, 4, 5]
ar3 = ar1 + ar2 # => [1, 2, 3, 3, 4, 5]
Now if you want to remove duplicates, use Array#uniq:
ar4 = ar3.uniq # => [1, 2, 3, 4, 5]
There is no need to write a method to do any of this since the Ruby Array class already supports it. You should skim through the documentation of the Array class to learn more things you can do with arrays.
What do you mean 'not working'?
Similar questions have been asked here:
Array Merge (Union)
You have two options: the pipe operator (a1 | a2) or concatenate-and-uniq ((a1 + a2).uniq).
Also be careful about using <<, this will modify the original variable, concatenating ar2 onto the end of the original ar1.
nums1 = Array[1, 2, 3, 4, 5]
nums2 = Array[5, 6, 7, 8, 9]
result = (nums1<< nums2).flatten!
nums1
=> [1, 2, 3, 4, 5, 5, 6, 7, 8, 9]
nums2
=> [5, 6, 7, 8, 9]
result
=> [1, 2, 3, 4, 5, 5, 6, 7, 8, 9]
Additionally- just another Ruby tip, you do not need the destructive flatten! with ! versus the regular flatten. The regular flatten method will return a new Array, which you assign to result in your case. flatten! will flatten self in place, altering whatever Array it's called upon, rather than returning a new array.
You can merge Arrays using '+' operator and you can ignore the duplicated values using .uniq
>> nums1 = Array[1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
>> nums2 = Array[5, 6, 7, 8, 9]
=> [5, 6, 7, 8, 9]
>> def mergeArrays (nums1, nums2)
>> result = (nums1 + nums2).uniq
>> end
=> :mergeArrays
>> mergeArrays(nums1,nums2)
=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
nums1 = Array[1, 2, 3, 4, 5]
nums2 = Array[5, 6, 7, 8, 9]
p nums1.concat(nums2).uniq

Why does my hash have the same key mapped to multiple values?

I have a hash that maps an array of integers to an integer. For some reason the hash has one key mapped to multiple values like:
{[1,2]=>3, [1,2]=> 4}
How can I prevent this from happening? Running
for key, value in map
puts key.inspect + "=>" + value.inspect + ":" + key.hash.inspect
end
gives me
[1, 2]=>11:11
[0, 4, 6, 8, 9]=>10:253
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]=>15:11189
[0, 3, 4, 6, 7, 8, 9]=>13:981
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]=>14:11189
[0, 1, 2, 4, 5, 6, 7, 8, 9]=>12:4661
I can think of two cases. The first has the obscure compare_by_identity switched on. Don't know what to do about it. Don't switch it on? Copy everything to a normal hash?
h={}
h.compare_by_identity
h[[1,2]]=2
h[[1,2]]=3
p h #=> {[1, 2]=>2, [1, 2]=>3}
The second case is more plausible: the key gets changed after being put in the hash.
h={}
h[[1,2,3]]=2
h[[1,2]]=3
h.keys.first.pop # assuming ruby 1.9
p h #=> {[1, 2]=>2, [1, 2]=>3}
That's easy to remedy (but also easy to forget):
h.rehash
p h #=> {[1, 2]=>3}

how to get an order-specified subset of an array of variable length from an array of variable length?

I have an array of objects of variable length n. Defined by the number of records in my database.
I need a function to grab subsets (keeping the objects in order and always beginning at index 0) of the array of specified length m where m can be any integer I pass in.
e.g. if n = 10 and m = 4
array foo = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
subset a = [0, 1, 2, 3]
subset b = [4, 5, 6, 7]
subset c = [8, 9]
So, I need to programmatically be able to say, "Give me the i-th subset of length m from an array, given the array is length n." Using the previous example: "Give me the second subset of length four from foo" => returns the items at positions [4, 5, 6, 7].
I hope that made sense. Assistance with a ruby solution would be much appreciated! thx!
foo.each_slice(subset_length).to_a[subset_index]
e.g. foo.each_slice(4).to_a[2] returns "the second subset of length four from foo".
You can use Enumerable#each_slice:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(4).to_a
#=> [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9]]

Resources