What is the difference between map and collect in ruby [duplicate] - ruby

This question already has answers here:
Difference between map and collect in Ruby?
(6 answers)
Closed 6 years ago.
puts "Example of each"
x = [1,2,3]
a = x.each{ |i|
i+1
}
puts a.inspect
puts x.inspect
puts "Example of map"
b = x.map{ |i|
i+1
}
puts b.inspect
puts x.inspect
puts "Example of collect"
c = x.collect{ |i|
i+1
}
puts c.inspect
puts x.inspect
Output
Example of each
[1, 2, 3]
[1, 2, 3]
Example of map
[2, 3, 4]
[1, 2, 3]
Example of collect
[2, 3, 4]
[1, 2, 3]
Here we see each block returns the same value passed to it irrespective of the operation inside it. And the map and collect seems to be same. So basically what is the difference between map and collect?

Absolutely nothing, it's an alias.

Related

A single method to delete! elements from Array by predicate and return deleted

I couldn't find a method in docs to do the following:
a = [1, 2, 3]
b = a.remove! {|x| x > 1}
puts a # [1]
puts b # [2, 3]
There is a select! method that does similar thing but it doesn't accept a predicate.
To my disappointment, delete_if, keep_if, reject! and select! mutate the array but also return the same array.
Currently, I achieve a desired in 2 steps like this but maybe there are better/smarter options?
a = [1, 2, 3]
b = a.reject {|x| x > 1}
a = a - b
puts a # [1]
puts b # [2, 3]
I don't know a way to accomplish that in 1 step, however if as in your 2nd example you'd accept to not mutate a from the ruby method, you could use Enumerable#partition
a = [1, 2, 3]
# note that b is first because first array is for elements returning true
b, a = a.partition { |x| x > 1 }
puts a # [1]
puts b # [2, 3]

New array declaration in Ruby

In Ruby, what is the difference between:
new_array = old_array
and
new_array = Array.new(old_array)
The first one is assignment, and will not create a new object. The second one is invalid (under default definition of Object), and will raise an argument error.
Consider the following:
old_arr = [1,2,3] #=> [1, 2, 3]
old_arr.object_id #=> 70142672048160
new_arr = old_arr #=> [1, 2, 3]
new_arr.object_id #=> 70142672048160
newer_arr = Array.new(old_arr) #=> [1, 2, 3]
newer_arr.object_id #=> 70142675883800
So you see the local variables old_arr and new_arr hold the same array object. By contrast, the variable newer_arr holds a different array object.
Now try this:
old_arr[0] = 'X' #=> "X"
old_arr #=> ["X", 2, 3]
then
new_arr #=> ["X", 2, 3]
newer_arr #=> [1, 2, 3]
newer_arr points to what is called a "shallow copy" of old_arr. To see what this means, consider another example:
old_arr = [1,2,[3,4]] #=> [1, 2, [3, 4]]
new_arr = old_arr #=> [1, 2, [3, 4]]
newer_arr = Array.new(old_arr) #=> [1, 2, [3, 4]]
old_arr[0] = 'X' #=> "X"
old_arr[2][0] = 'Y' #=> "Y"
old_arr #=> ["X", 2, ["Y", 4]]
new_arr #=> ["X", 2, ["Y", 4]]
newer_arr #=> [1, 2, ["Y", 4]]
As before, newer_arr[0] has not been modified, and newer_arr[2] contains the same object as it did previously, but that object has been modified.
"what happens in case we use an Array or String instead of Object?"
That depends on the class definition itself, so you should look at the documentation.
Basically, #new method creates a new object and then calls "initialize" method with parameters passed to it.
To answer your question:
Array.new method copies the array passed to it (actually, as i said before: it passes that array to initialize method, which copies it).
Same happens with String.
The easiest way to know such things is actually repl.
In irb execute following lines, one by one:
a = ":)"
b = a
a[1] = '('
puts a
puts b
a = ":)"
b = String.new(a)
a[1] = '('
puts a
puts b
a = [1,2,3]
b = a
a[1] = 10
puts a
puts b
a = [1,2,3]
b = Array.new(a)
a[1] = 10
puts a
puts b

Iterator calls all elements at once within an each block

I build the array here:
def initialize
#names = []
end
#names << page.all('//*[#id="USERS_AVAIL"]/option').map {|result| result.text.split(", ")}
later on I'm trying to compile and visit url's by iterating through the names array like so:
#names.each do |name|
visit "https://example.com/k=#{name}&tpe=1"
end
Some puts statements show me that the each method is calling every element of the array all at once instead of iterating as intended. I.E.: "https://example.com/k=#{[[%22Adviento%22,%20%22Justin%22],%20[%22Asamoah%22,%20%22Nathan%22],%20[%22Baughman%22,%20%22Zachary%22],}&tpe=1". #names.length has a count of only 4 but a puts of the #names array shows the proper output? I'm not sure what could be wrong, thanks in advance for any assist.
Replace << with +=. The << is inserting the entire array as a single element of its own, whereas += will concatenate the array, which seems to be your intention.
For example:
a = [1,2,3]
# => [1, 2, 3]
a << [4,5,6]
# => [1, 2, 3, [4, 5, 6]] # WRONG
a = [1,2,3]
# => [1, 2, 3]
a += [4,5,6]
# => [1, 2, 3, 4, 5, 6] # CORRECT
Try:
#names += page.all('//*[#id="USERS_AVAIL"]/option')
.map { |r| r.text.split(',').map(&:strip) }.flatten
If the quotes are in the literal form %22 and you want to capture the strings in between them:
#names += page.all('//*[#id="USERS_AVAIL"]/option')
.map { |r| r.text.scan(/%22([^%]+)%22/) }.flatten

Inverting an array of arrays (matrix) in ruby

I have "text" which is an array of arrays, let's say:
1 2 3
4 5 6
7 8 9
and I just want to create another array of arrays but like this:
1 4 7
2 5 8
3 6 9
I cant get it working. It says: undefined method '[]=' for nil:NilClass
vect = Array.new()
3.times{|i|
3.times{|j|
vect[j][i] = text[i][j]
}
}
"text" is not a very good name for an array of arrays containing integers. That said, you might want to look into array.transpose.
You declare an empty array, but you don't fill it in with empty arrays.
Because the array you are using is empty, vect[j] will always return nil and not an array as you expect.
Here is the corrected code:
vect = [[], [], [], []]
4.times do |i|
4.times do |j|
vect[j][i] = text[i][j]
end
end
You can also you the Matrix class for those purposes, for instance:
require 'matrix'
m1 = Matrix[[1,2,3], [4,5,6],[7,8,9]]
m1.to_a.each {|r| puts r.inspect} #=> This is just print the matrix in that format.
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
- Transposed Version -
m1.transpose.to_a.each {|r| puts r.inspect} #=> Note the method `transpose` called. The rest is just for printin.
[1, 4, 7]
[2, 5, 8]
[3, 6, 9]

Distinct difference between collect and each? [duplicate]

This question already has answers here:
what's different between each and collect method in Ruby [duplicate]
(7 answers)
Closed 8 years ago.
Using arrays what's the main difference between collect and each? Preference?
some = []
some.collect do {|x| puts x}
some.each do |x|
puts x
end
array = [] is a shortcut to define an array object (long form: array = Array.new)
Array#collect (and Array#map) return a new array based on the code passed in the block. Array#each performs an operation (defined by the block) on each element of the array.
I would use collect like this:
array = [1, 2, 3]
array2 = array.collect {|val| val + 1}
array.inspect # => "[1, 2, 3]"
array2.inspect # => "[2, 3, 4]"
And each like this:
array = [1, 2, 3]
array.each {|val| puts val + 1 }
# >> 2
# >> 3
# >> 4
array.inspect # => "[1, 2, 3]"
Hope this helps...
collect (or map) will "save" the return values of the do block in a new array and return it, example:
some = [1,2,3,10]
some_plus_one = some.collect {|x| x + 1}
# some_plus_one == [2,3,4,11]
each will only execute the do block for each item and wont save the return value.

Resources