Mapping an array to a hash?

Hi,

Can anyone suggest an idiomatic ruby equivalent to this perl snippet?

   my %index = map { $_ => compute_something($_) } @files;

Where @files is an array of filenames, and compute_something is a subroutine which does some probably expensive operation on the file.

The result is a hash indexing the file name to the computed result for that file. This and it's grep equivalent is something I find quite quite handy in perl.

The best I came up with so far seems reletively clunky to me:

   index = Hash.new()
   files.each {|f| index[f] = compute_something(f) }

or:

   index = files.inject(Hash.new) {|i,f| i[f] = compute_something(f); i }

I was wondering if there's a more succinct and readable way?

TIA,

Nick

Nick Woolley wrote:

Hi,

Can anyone suggest an idiomatic ruby equivalent to this perl snippet?

  my %index = map { $_ => compute_something($_) } @files;

Where @files is an array of filenames, and compute_something is a subroutine which does some probably expensive operation on the file.

The result is a hash indexing the file name to the computed result for that file. This and it's grep equivalent is something I find quite quite handy in perl.

The best I came up with so far seems reletively clunky to me:

  index = Hash.new()
  files.each {|f| index[f] = compute_something(f) }

or:

  index = files.inject(Hash.new) {|i,f| i[f] = compute_something(f); i }

I was wondering if there's a more succinct and readable way?

I'm not aware of anything more succinct to do what you wrote here, but if you want to defer the expensive operation, you can do this:

index = Hash.new { |h,f| h[f] = compute_something(f) }

Maybe there should be something like this:

class Array
   def hashmap
     h={}
     each {|x| h = yield x}
     h
   end
end

[1,2,3].hashmap {|x| x*10}
# => {1=>10, 2=>20, 3=>30}

If you want mind bending and obscure, try...

index = Hash.new{|hash,key| hash[key] = compute_something(key)}

and then somewhere totally elsewhen in the code...

files.each{|f| index[f]}

John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john.carter@tait.co.nz
New Zealand

Somewhere on the edge of a Galaxy, one of literally billions of such
galaxies, is a sun, one of literally billions of suns in that
galaxy.

Orbiting that sun is a small rock 330000 times smaller than that
sun.

This rock is covered by a very very thin scum of life. (Think 6000km
of rock followed by a meter or so of biomass.)

Amongst the millions of species in that scum are many hundreds of
thousands of types beetle and a mere handful of primates.

Surprisingly enough, this email does not originate from a beetle.

It originates from just one of the 6 billion vastly outnumbered humans.

I trust you will keep this perspective and context in mind when
reacting to this email.

···

On Wed, 4 May 2005, Nick Woolley wrote:

Can anyone suggest an idiomatic ruby equivalent to this perl snippet?

my %index = map { $_ => compute_something($_) } @files;

The best I came up with so far seems reletively clunky to me:

index = Hash.new()
files.each {|f| index[f] = compute_something(f) }

index = Hash::new{|h,f| h[f] = compute_something f}

hashes can take a block to define how to initialize new values based on keys.

one benefit is that this means the 'compute_something' bit is lazy.

hth.

-a

···

On Wed, 4 May 2005, Nick Woolley wrote:

Hi,

Can anyone suggest an idiomatic ruby equivalent to this perl snippet?

  my %index = map { $_ => compute_something($_) } @files;

Where @files is an array of filenames, and compute_something is a
subroutine which does some probably expensive operation on the file.

The result is a hash indexing the file name to the computed result for
that file. This and it's grep equivalent is something I find quite
quite handy in perl.

The best I came up with so far seems reletively clunky to me:

  index = Hash.new()
  files.each {|f| index[f] = compute_something(f) }

or:

  index = files.inject(Hash.new) {|i,f| i[f] = compute_something(f); i }

I was wondering if there's a more succinct and readable way?

TIA,

Nick

--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
renunciation is not getting rid of the things of this world, but accepting
that they pass away. --aitken roshi

===============================================================================

Wouldn't it make more sense to put #hashmap in module Enumerable?
Just a thought.

···

On 5/3/05, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:

class Array
   def hashmap
     h={}
     each {|x| h = yield x}
     h
   end
end

[1,2,3].hashmap {|x| x*10}
# => {1=>10, 2=>20, 3=>30}

"John Carter" <john.carter@tait.co.nz> schrieb im Newsbeitrag news:Pine.LNX.4.61.0505041025210.25628@parore.tait.co.nz...

Can anyone suggest an idiomatic ruby equivalent to this perl snippet?

my %index = map { $_ => compute_something($_) } @files;

The best I came up with so far seems reletively clunky to me:

index = Hash.new()
files.each {|f| index[f] = compute_something(f) }

If you want mind bending and obscure, try...

index = Hash.new{|hash,key| hash[key] = compute_something(key)}

and then somewhere totally elsewhen in the code...

files.each{|f| index[f]}

That's not really equivalent to what Nick requested and it's more clunky also.

I prefer a solution with - guess what - #inject, but Hash does work, too:

a = [1,2,3]

=> [1, 2, 3]

a.inject({}) {|h,i| h[i]=i+10; h}

=> {1=>11, 2=>12, 3=>13}

Hash[ *a.map{|i| [i,i+10]}.flatten ]

=> {1=>11, 2=>12, 3=>13}

Kind regards

    robert

···

On Wed, 4 May 2005, Nick Woolley wrote:

Logan Capaldo wrote:

···

On 5/3/05, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:

class Array
  def hashmap
    h={}
    each {|x| h = yield x}
    h
  end
end

[1,2,3].hashmap {|x| x*10}
# => {1=>10, 2=>20, 3=>30}

Wouldn't it make more sense to put #hashmap in module Enumerable?
Just a thought.

Of course. It would also probably make sense to choose a better name. #map_to_hash, maybe?.