Soliciting some help with inject method

Rubysters,

I think I am not wrong if I can solicit some knowledge. :slight_smile:

Can any one help modify this code?

I have:
array = [[‘a’, 1], [‘b’, 2], [‘a’,2], [‘c’,4], [‘d’, 5], [‘b’,4]]

I want to create a hash using inject method:

hash = {‘a’ => [1, 2], ‘b’ => [2, 4], ‘c’ => [4], ‘d’ => [5]}

The following code gives: {“a”=>[2], “b”=>[4], “c”=>[4], “d”=>[5]}

hash = array.inject({}) do |result, array|
new_hash = {}
new_hash[array.first] = [array.last]
result.merge!(new_hash) # I have tried result.update(new_hash) but it
fails
too
result
end

Here is a console friendly version of the same:
hash = array.inject({}){|result, array| new_hash = {};
new_hash[array.first] = [array.last]; result.merge!(new_hash); result;}

Thanks in advance,


Edmond
Software Developer | Baobab Health Trust (http://www.baobabhealth.org/)
|
Malawi

Cell: +265 999 465 137 | +265 881 234 717

I wish you a Merry Christmas and a Prosperous New Year 2011!!*
*

On 2/2/2011 8:56 AM, Edmond K. wrote:

hash = {‘a’ => [1, 2], ‘b’ => [2, 4], ‘c’ => [4], ‘d’ => [5]}
array.inject({}) do |result, (key, value)|
(result[key] ||= []) << value
result
end

-Jeremy

You can do this without an inject, with a simple iteration and a bit of
||=

a = [[‘a’, 1], [‘b’, 2], [‘a’,2], [‘c’,4], [‘d’, 5], [‘b’,4]]
=> [[“a”, 1], [“b”, 2], [“a”, 2], [“c”, 4], [“d”, 5], [“b”, 4]]

h = {}
=> {}

a.each { |k, v| h[k] ||= []; h[k] << v }
=> [[“a”, 1], [“b”, 2], [“a”, 2], [“c”, 4], [“d”, 5], [“b”, 4]]

h
=> {“a”=>[1, 2], “b”=>[2, 4], “c”=>[4], “d”=>[5]}

On Wed, Feb 2, 2011 at 2:56 PM, Edmond K. <

On Wed, Feb 2, 2011 at 3:56 PM, Edmond K.
[email protected] wrote:

hash = {‘a’ => [1, 2], ‘b’ => [2, 4], ‘c’ => [4], ‘d’ => [5]}

Here is a console friendly version of the same:
hash = array.inject({}){|result, array| new_hash = {};
new_hash[array.first] = [array.last]; result.merge!(new_hash); result;}

Thanks in advance,

Yet another way without inject:

irb(main):001:0> array = [[‘a’, 1], [‘b’, 2], [‘a’,2], [‘c’,4], [‘d’,
5], [‘b’,4]]
=> [[“a”, 1], [“b”, 2], [“a”, 2], [“c”, 4], [“d”, 5], [“b”, 4]]
irb(main):002:0> result = Hash.new {|h,k| h[k] = []}
=> {}
irb(main):003:0> array.each {|key,value| result[key] << value}
=> [[“a”, 1], [“b”, 2], [“a”, 2], [“c”, 4], [“d”, 5], [“b”, 4]]
irb(main):004:0> result
=> {“a”=>[1, 2], “b”=>[2, 4], “c”=>[4], “d”=>[5]}

Jesus.

Here’s one simple way to do it:

hash = array.inject({}) do |result, array|
key,val = array
if result[key].nil?
result[key] = [val]
else
result[key].push val
end
result
end

On Wed, Feb 2, 2011 at 9:56 AM, Edmond K. <

Le 2 fvrier 2011 17:46:42 UTC+2, edmond.kachale <
[email protected]> a crit :

else
result
end

Sorry, I meant Andrew.

But I also value you contribution, Adam and Jess. In fact, I think your
methods are faster than the inject’s way.


Edmond
Software Developer | Baobab Health Trust (http://www.baobabhealth.org/)
|
Malawi

Cell: +265 999 465 137 | +265 881 234 717*
**
An old dog does not hunt because of speed, but his endurance of the
heart.*
*
*

2011/2/2 Andrew W. [email protected]

end

Thanks Adam. I just reduced your lines to make it geeky!! :slight_smile:

hash = array.inject({}) do |result, (key, value)|
(result[key].nil?) ? (result[key] = [value]) :
(result[key].push(value))
result
end


Edmond
Software Developer | Baobab Health Trust (http://www.baobabhealth.org/)
|
Malawi

Cell: +265 999 465 137 | +265 881 234 717*
**
An old dog does not hunt because of speed, but his endurance of the
heart*

But I also value you contribution, Adam and Jess. In fact, I think your
methods are faster than the inject’s way.

You’d be surprised :-). If I didn’t do anything wrong (I usually make
mistakes when benchmarking), my method is the slowest:

require ‘benchmark’

TIMES = 100_000
array = [[‘a’, 1], [‘b’, 2], [‘a’,2], [‘c’,4], [‘d’, 5], [‘b’,4]]

Benchmark.bm do |x|
x.report “inject Jeremy” do
TIMES.times do
array.inject({}) do |result, (key, value)|
(result[key] ||= []) << value
result
end
end
end

x.report “Adam” do
TIMES.times do
result = {}
array.each { |k, v| result[k] ||= []; result[k] << v }
end
end

x.report “inject Andrew” do
TIMES.times do
hash = array.inject({}) do |result, values|
key,val = values
if result[key].nil?
result[key] = [val]
else
result[key].push val
end
result
end
end
end

x.report “Jesus” do
TIMES.times do
result = Hash.new {|h,k| h[k] = []}
array.each {|key,value| result[key] << value}
end
end
end

$ ruby bm_inject.rb
user system total real
inject Jeremy 1.440000 0.300000 1.740000 ( 1.770496)
Adam 1.100000 0.190000 1.290000 ( 1.290073)
inject Andrew 1.810000 0.210000 2.020000 ( 2.064162)
Jesus 1.800000 0.320000 2.120000 ( 2.118433)

I guess it’s because you need to call the default proc many times, as
opposed to the other methods, which don’t have any proc to call or
block to yield to.

Jesus.

On Wed, Feb 2, 2011 at 11:52 PM, Edmond K. > But I also value you
contribution,

… are faster than the inject’s way.

inject is a lot faster in 1.9
its added adv is that you lessen the use of temp vars and everything
is encap in the method…

eg, using jeremy bopps technique, one would do

a.inject(Hash.new{|hash,key| hash[key]=[]}) do |hash,(key,value)|
hash[key] << value
hash
end

or add a touch of tap,

a.inject(Hash.new{|h,k| h[k]=[]}) do |h,(k,value)|
h.tap{|h| h[k] << value}
end

best regards -botp