I'm trying to use the map function to combine an array of arrays into an array of arrays that eliminate a unique value in arr[0][0] but pull arr[0][1] and group it with the corresponding unique value.
arr = [[a, 1], [a, 2], [b,3], [b, 4]]
=> [[a, [1, 2]], [b, [3,4]]]
I'm sure this is pretty basic but I'm rather new to coding in general. Thank you for your help.
Try this:
arr = [[:a, 1], [:a, 2], [:b, 3], [:b, 4]]
arr.group_by(&:first).map { |k, v| [k, v.map(&:last)] }
#=> [[:a, [1, 2]], [:b, [3, 4]]]
Depending on what your goal is, you might want to turn the result into a hash:
Hash[arr.group_by(&:first).map { |k, v| [k, v.map(&:last)] }]
#=> {:a=>[1, 2], :b=>[3, 4]}
Related
In the code below, arr is meant to be a two-dimensional array, such as [[1,2],[4,5]]. It computes the sum of the elements of the sub arrays. A subarray can have only one element, in which case the sum is just that one element.
def compute(arr)
return nil unless arr
arr.map { |(a, b)| !b.nil? ? a + b : a }
end
Why does the code have to be |(a, b)| instead of |a,b|?
What does (a,b) mean in Ruby?
You could use |a,b| too, it's nothing different from |(a,b)|.
You may also rewrite the code as below, which doesn't have the element number limit for the sub arrays:
arr.map { |a| a.inject{ |sum,x| sum + x } }
or even:
arr.map { |a| a.inject(:+) }
Both are equivalent if arr is an array:
arr = [[1, 2], [4, 5]]
arr.map { |a, b| [a, b] } #=> [[1, 2], [4, 5]]
arr.map { |(a, b)| [a, b] } #=> [[1, 2], [4, 5]]
This is because the block is called with a single argument at a time: the subarray. Something like:
yield [1, 2]
yield [4, 5]
This changes if more than one arguments is yielded. each_with_index for example, calls the block with two arguments: the item (i.e. the subarray) and its index. Something like:
yield [1, 2], 0
yield [4, 5], 1
The difference is obvious:
enum = [[1, 2], [4, 5]].each_with_index
enum.map { |a, b| [a, b] } #=> [[[1, 2], 0], [[4, 5], 1]]
enum.map { |(a, b)| [a, b] } #=> [[1, 2], [4, 5]]
Note that omitting parenthesis also allows you to set a default argument value:
arr = [[1, 2], [4]]
arr.map { |a, b = 0| a + b } #=> [3, 4]
I'm trying to learn how to search within a two-dimensional array; for example:
array = [[1,1], [1,2], [1,3], [2,1], [2,4], [2,5]]
I want to know how to search within the array for the arrays that are of the form [1, y] and then show what the other y numbers are: [1, 2, 3].
If anyone can help me understand how to search only with numbers (as a lot of the examples I found include strings or hashes) and even where to look for the right resources even, that would be helpful.
Ruby allows you to look into an element by using parentheses in the block argument. select and map only assign a single block argument, but you can look into the element:
array.select{|(x, y)| x == 1}
# => [[1, 1], [1, 2], [1, 3]]
array.select{|(x, y)| x == 1}.map{|(x, y)| y}
# => [1, 2, 3]
You can omit the parentheses that correspond to the entire expression between |...|:
array.select{|x, y| x == 1}
# => [[1, 1], [1, 2], [1, 3]]
array.select{|x, y| x == 1}.map{|x, y| y}
# => [1, 2, 3]
As a coding style, it is a custom to mark unused variables as _:
array.select{|x, _| x == 1}
# => [[1, 1], [1, 2], [1, 3]]
array.select{|x, _| x == 1}.map{|_, y| y}
# => [1, 2, 3]
You can use Array#select and Array#map methods:
array = [[1,1], [1,2], [1,3], [2,1], [2,4], [2,5]]
#=> [[1, 1], [1, 2], [1, 3], [2, 1], [2, 4], [2, 5]]
array.select { |el| el[0] == 1 }
#=> [[1, 1], [1, 2], [1, 3]]
array.select { |el| el[0] == 1 }.map {|el| el[1] }
#=> [1, 2, 3]
For more methods on arrays explore docs.
If you first select and then map you can use the grep function to to it all in one function:
p array.grep ->x{x[0]==1}, &:last #=> [1,2,3]
Another way of doing the same thing is to use Array#map together with Array#compact. This has the benefit of only requiring one block and a trivial operation, which makes it a bit easier to comprehend.
array.map { |a, b| a if b == 1 }
#=> [1, 2, 3, nil, nil, nil]
array.map { |a, b| a if b == 1 }.compact
#=> [1, 2, 3]
You can use each_with_object:
array.each_with_object([]) { |(x, y), a| a << y if x == 1 }
#=> [1, 2, 3]
i want to convert in ruby
[[1, 1], [2, 3], [3, 5], [4, 1], [1, 2], [2, 3], [3, 5], [4, 1]]
into
[{1=>1}, {2=>3}, {3=>5}, {4=>1}, {1=>2}, {2=>3}, {3=>5}, {4=>1}]
and after this to obtain sum of all different keys:
{1=>3,2=>6,3=>10,4=>2}
For the second question
sum = Hash.new(0)
original_array.each{|x, y| sum[x] += y}
sum # => {1 => 3, 2 => 6, 3 => 10, 4 => 2}
Functional approach:
xs = [[1, 1], [2, 3], [3, 5], [4, 1], [1, 2], [2, 3], [3, 5], [4, 1]]
Hash[xs.group_by(&:first).map do |k, pairs|
[k, pairs.map { |x, y| y }.inject(:+)]
end]
#=> {1=>3, 2=>6, 3=>10, 4=>2}
Using Facets is much simpler thanks to the abstractions map_by (a variation of group_by) and mash (map + Hash):
require 'facets'
xs.map_by { |k, v| [k, v] }.mash { |k, vs| [k, vs.inject(:+)] }
#=> {1=>3, 2=>6, 3=>10, 4=>2}
You don't need the intermediate form.
arrays = [[1, 1], [2, 3], [3, 5], [4, 1], [1, 2], [2, 3], [3, 5], [4, 1]]
aggregate = arrays.each_with_object Hash.new do |(key, value), hash|
hash[key] = hash.fetch(key, 0) + value
end
aggregate # => {1=>3, 2=>6, 3=>10, 4=>2}
arr= [[1, 1], [2, 3], [3, 5], [4, 1], [1, 2], [2, 3], [3, 5], [4, 1]]
final = Hash.new(0)
second_step = arr.inject([]) do |arr,inner|
arr << Hash[*inner]
final[inner.first] += inner.last
arr
end
second_step
#=> [{1=>1}, {2=>3}, {3=>5}, {4=>1}, {1=>2}, {2=>3}, {3=>5}, {4=>1}]
final
#=> {1=>3, 2=>6, 3=>10, 4=>2}
if you directly only need the last step
arr.inject(Hash.new(0)){|hash,inner| hash[inner.first] += inner.last;hash}
=> {1=>3, 2=>6, 3=>10, 4=>2}
I have two arrays,
a = [1, 2]
b = [:a]
I want to get the result as
[[1, :a], [2, :a]]
Is there any methods for this?
Use the Array#product:
a = [1, 2]
b = [:a]
a.product(b)
=> [[1, :a], [2, :a]]
Also you can do it this way
[a,b*a.size].transpose
#=> [[1, :a], [2, :a]]
In Ruby 1.9.x I have a hash that maintains its order
hsh = {9=>2, 8=>3, 5=>2, 4=>2, 2=>1}
Is there a way to get say the key of the third element other than this:
hsh.to_a[2][0]
Try using Hash#keys and Hash#values:
thirdKey = hsh.keys[2]
thirdValue = hsh.values[2]
Why do you use hash instead of an array? The array fits perfect for ordered collections.
array = [[9, 2], [8, 3], [5, 2], [4, 2], [2, 1]]
array.each { |pair| puts pair.first }
Sorting of arrays is very simple, ultimately.
disordered_array = [[4,2], [9,2], [8,3], [2,1], [5,2]]
disordered_array.sort { |a,b| b <=> a }
=> [[9, 2], [8, 3], [5, 2], [4, 2], [2, 1]]
Correct me if I'm wrong.