Hash#map_pairs

J

jeff_alexander_44

class Hash
def map_pairs
result = Array.new
self.each_pair { |k, v|
result << yield(k, v)
}
result
end
end

h = {
"a" => "x",
"b" => "y",
}
puts h.map_pairs { |k, v| "#{k} => #{v}" }.join(", ")

I was surprised to discover there was no Hash#map_pairs. I have found
that chaining transformations is usually better than the
iterative/imperative style implied by Hash#each_pair.

On second thought, it looks like this does the same thing:

puts h.to_a.map { |k, v| "#{k} => #{v}" }.join(", ")

But this fails to convey the programmer's idea in the same way that
map_pairs does. It is also needlessly inefficient, using a whole
extra temp array.
 
A

ara.t.howard

class Hash
def map_pairs
result = Array.new
self.each_pair { |k, v|
result << yield(k, v)
}
result
end
end

h = {
"a" => "x",
"b" => "y",
}
puts h.map_pairs { |k, v| "#{k} => #{v}" }.join(", ")

I was surprised to discover there was no Hash#map_pairs. I have found
that chaining transformations is usually better than the
iterative/imperative style implied by Hash#each_pair.

On second thought, it looks like this does the same thing:

puts h.to_a.map { |k, v| "#{k} => #{v}" }.join(", ")

But this fails to convey the programmer's idea in the same way that
map_pairs does. It is also needlessly inefficient, using a whole
extra temp array.

harp:~ > cat a.rb
class Hash
def map_pairs
result = Array.new
self.each_pair { |k, v|
result << yield(k, v)
}
result
end
end

h = {
"a" => "x",
"b" => "y",
}

puts h.map_pairs { |k, v| "#{k} => #{v}" }.join(", ")
puts h.map{ |k, v| "#{k} => #{v}" }.join(", ") ### ;-)


harp:~ > ruby a.rb
a => x, b => y
a => x, b => y


-a
 
J

jeff_alexander_44

Aha, thanks.

I was fooled by ri's output. My eyes went straight to the "Instance
methods" section. Since "map" is an instance method, shouldn't it be
listed under "Instance methods"? I now see that it's listed under
"Includes" --- which is fine, in addition to "Instance methods".
 
C

Chris Carter

Aha, thanks.

I was fooled by ri's output. My eyes went straight to the "Instance
methods" section. Since "map" is an instance method, shouldn't it be
listed under "Instance methods"? I now see that it's listed under
"Includes" --- which is fine, in addition to "Instance methods".
It is mixed in from the Enumerable module. It has lots of cool
functions. You should check it out, since Hash has them all as well
as Array.
 
A

ara.t.howard

Aha, thanks.

I was fooled by ri's output. My eyes went straight to the "Instance
methods" section. Since "map" is an instance method, shouldn't it be
listed under "Instance methods"? I now see that it's listed under
"Includes" --- which is fine, in addition to "Instance methods".

it's mixed in from enumerable - in fact the impl is much like you rolled on
your own. there are a ton of useful methods from enumerable implemented in
terms of #each. i suppose it's debatable where the docs should appear but i
personally think it's best to be clear and doccument them in enumerable where
they are defined.

cheers.

-a
 
J

jeff_alexander_44

$ irb
irb(main):001:0> Hash.instance_methods.include? "map"
=> true

So one would expect "map" to appear under "Instance methods" in ri.
Of course it comes from a mixin. That's not the issue here. The
existence of this thread is a data point.

Thus ensues the eternal struggle between those who are accustomed to
the idiosyncrasies and those who are driven insane by them.
 
A

ara.t.howard

$ irb
irb(main):001:0> Hash.instance_methods.include? "map"
=> true

So one would expect "map" to appear under "Instance methods" in ri.
Of course it comes from a mixin. That's not the issue here. The
existence of this thread is a data point.

Thus ensues the eternal struggle between those who are accustomed to
the idiosyncrasies and those who are driven insane by them.

ruby is a dangerous place to be if that sort of thing drives a fellow insane:

harp:~ > irb -r ostruct

irb(main):001:0> os = OpenStruct.new
=> #<OpenStruct>

irb(main):002:0> os.methods.grep /foobar/
=> []

irb(main):003:0> os.foobar = 42
=> 42

irb(main):004:0> os.foobar
=> 42


-a
 
J

jeff_alexander_44

Person A: "Here is a needless idiosyncrasy: ..."
Person B: "I can produce apparent idiosyncratic behavior with
method_missing."
Person A: "Well, of course. But what about the idiosyncrasy I
mentioned?"

The struggle continues...
 
R

Rick DeNatale

class Hash
def map_pairs
result = Array.new
self.each_pair { |k, v|
result << yield(k, v)
}
result
end
end

h = {
"a" => "x",
"b" => "y",
}
puts h.map_pairs { |k, v| "#{k} => #{v}" }.join(", ")

I was surprised to discover there was no Hash#map_pairs. I have found
that chaining transformations is usually better than the
iterative/imperative style implied by Hash#each_pair.

In Ruby 1.9 , at least as it stands today, 'each-like' methods like
each_pair will return an Enumerator if you don't give them a block,
this allows a nice ability to chain transformations.

rick@frodo:/public/rubysource/ruby1.8.5$ irb1.9
irb(main):001:0> {:a => 1, :b => 2}.each_pair
=> #<Enumerable::Enumerator:0xb7bd2650>
irb(main):002:0> {:a => 1, :b => 2}.each_pair.map {|k,v| [v,k]}
=> [[2, :b], [1, :a]]
irb(main):003:0>
 
M

Matthew Rudy

I've been looking at this of late,

what I want is ;

class Hash
def map_pairs
new_hash = self.class.new # works in HashWithIndifferentAccess
self.each do |key, value|
new_key, new_value = yield(key, value)
new_hash[new_key] = new_value
end
return new_hash
end

def map_values
new_hash = self.class.new
self.each do |key, value|
new_hash[key] = yield(key, value)
end
return new_hash
end
end

is that a bad idea?
does "map" have to return an array?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,077
Latest member
SangMoor21

Latest Threads

Top