Hash#each vs Hash#each_pair

#1

Sorry if this is a FAQ, but I’m curious to learn the rationale behind
having Hash#each be the same as Hash#each_pair instead of
Hash#each_value.

For my own (self-interested) case, I would prefer that Hash#each and
Array#each both iterate through the values of the container.

So, why are these different?

–wpd

#2

Patrick D. wrote:

Sorry if this is a FAQ, but I’m curious to learn the rationale behind
having Hash#each be the same as Hash#each_pair instead of
Hash#each_value.

For my own (self-interested) case, I would prefer that Hash#each and
Array#each both iterate through the values of the container.

So, why are these different?

–wpd

#!/usr/bin/ruby

hash = {1 => ‘one’, 2 => ‘two’, 3 => ‘three’}

p “p hash : #{hash}”
p “hash.each”
hash.each do |e| #e is [key,value]
p e
end

p “hash.each_pair”
hash.each_pair do |k,v| #k and v class as in hash
p “#{k}=#{v}”
end

p “hash.each_value”
hash.each_value do |e| #e is value
p e
end

#3

On Mon, Aug 18, 2008 at 3:25 PM, Patrick D. removed_email_address@domain.invalid
wrote:

Sorry if this is a FAQ, but I’m curious to learn the rationale behind
having Hash#each be the same as Hash#each_pair instead of
Hash#each_value.

For my own (self-interested) case, I would prefer that Hash#each and
Array#each both iterate through the values of the container.
Hmm, your approach is making some sense, I however believe that
Hash#each was chosen
pragmatically and very reasonably so, I guess that Hash#each is the
most used way to iterate over a hash and therefore it is quite
convenient to have a short name.
I also believe that #each shall mean “each” and keys being part of the
hash, yielding the keys and the values makes sense too.
HTH
Robert

So, why are these different?

–wpd


http://ruby-smalltalk.blogspot.com/

There’s no one thing that’s true. It’s all true.

#4

p “p hash : #{hash}”
p “hash.each”
hash.each do |e| #e is [key,value]
p e
end
I am just trying to understand why hash.each returns [key, value]
instead of value the way that array.each does:
#!/usr/bin/ruby

hash = {1 => ‘one’, 2 => ‘two’, 3 => ‘three’}
array = [‘one’, ‘two’, ‘three’]

p “p hash : #{hash}”
p “hash.each”
hash.each do |e| #e is [key,value]
p e
end

p “p array : #{array}”
p “array.each”
array.each do |e|
p e
end

The answer might be “because that’s the way it’s always been done, and
there’s no way we’re going to change it because a newbie asked for it
to be changed!”. (The careful reader might notice that I haven’t
asked for anything to be changed – I’m simply trying to understand
the thinking that went into the decision to make Hash#each operate
differently than Array#each)

In my case, I have some code in which a bunch of data has been
collected into an array, and I would like to modify my code such that
the collection of data is stored in a Hash instead of an Array object.
I had assumed that, since I used object.each everywhere that I
iterated through my data, it would be as simple as changing the code
where I stuff the values into the collection. Obviously, my
assumption proved incorrect. Which led me to the question, “Now, I
wonder why they did that?” So I’ve asked the question.

–wpd

#5

On Mon, Aug 18, 2008 at 3:46 PM, Mateusz T. removed_email_address@domain.invalid
wrote:

hash = {1 => ‘one’, 2 => ‘two’, 3 => ‘three’}

p “p hash : #{hash}”
p “hash.each”
hash.each do |e| #e is [key,value]
p e
end
Well explained indeed, it might however be worth noting for nubies
that the convenient

hash.each do |key, value|
end

works too.
BTW even

hash.each_pair{ |x| p x }

works, although it gives an expectable warning.
R.

#6

On Aug 18, 2008, at 9:56 AM, Patrick D. wrote:

array = [‘one’, ‘two’, ‘three’]
p e
collected into an array, and I would like to modify my code such that
the collection of data is stored in a Hash instead of an Array object.
I had assumed that, since I used object.each everywhere that I
iterated through my data, it would be as simple as changing the code
where I stuff the values into the collection. Obviously, my
assumption proved incorrect. Which led me to the question, “Now, I
wonder why they did that?” So I’ve asked the question.

–wpd

(It seems that my first response got swallowed by the web)

An Array contains elements, a Hash contains key-value pairs. Doesn’t
that make sense that Hash#each returns the pairs? It seems that your
mental picture of “values of the container” is at odds with Ruby (Matz).

You could alias Array#each_value to be Array#each and then use
each_value for both types.

Perhaps if your motivation for changing from Array to Hash was
eliminating duplication, you really want to use a Set
-Rob
Rob B. http://agileconsultingllc.com
removed_email_address@domain.invalid
+1 513-295-4739
Skype: rob.biedenharn

#7

On Aug 18, 11:38 am, Rob B. removed_email_address@domain.invalid
wrote:

An Array contains elements, a Hash contains key-value pairs. Doesn’t
that make sense that Hash#each returns the pairs? It seems that your
mental picture of “values of the container” is at odds with Ruby (Matz).

I think that mental picture would make more sense if there were such a
thing as an KeyValuePair. I think Hash#each was made that was simply
out of convenience, nothing more.

T.

#8

On Mon, Aug 18, 2008 at 6:08 PM, Patrick D. removed_email_address@domain.invalid
wrote:

But I realized (immediately) that Hash#each didn’t do the same
thing as Array#each.
You are making a statement here that I consider extremely unfair, how
can Hash#each do the same than Array#each.
Turned out the behavior of Hash#each was not suiting your abstraction
and you conclude that it is not doing the same? Pardon me if I am
upset, well I am not, but I could be right… ;).
same thing as the Hash#each_element iterator and you just use that

On a related note…
Would it make sense to propose adding an Array#each_value, aliased to
Array#each to the baseline language/library definition so that one
could use the same iterator independent of whether the underlying
container were a Hash or an Array?
Well maybe we were not quite clear enough, the above proposal is not
feasible, iterating over a hash cannot behave like iterating over an
array.
Would it make sense to propose
adding an #each_element iterator to both classes?
No it would not.

–wpd

Robert

#9

I think it would make sense to add the alias each_value to array for
each
since he is correct in that for an array the key is just a integer, and
the
value is just the array element, so in a sense there should be a
each_value
for array. I could add this to the Ruby core and submit, if anyone
thinks it
is a good idea.

#10

You could alias Array#each_value to be Array#each and then use each_value
for both types.

…which brings me to my next question… it seems strange to me that
I should be the first person to write some Ruby code who didn’t know
going into my project whether it made more sense to store my data as
an array or as a hash. Actually, I didn’t even think about it, I
simply started out with:
dataset = []
dataset << make_some_more_data()

(FWIW, my code now reads something like
dataset = Hash.new
dat = make_some_more_data()
dataset[dat.name] = dat
)

and later, when I looked at the resulting data and code, I realized
that I really wanted to index my data by it’s name, rather than some
arbitrary numeric index. But, at that point, I had written other code
that looked like

dataset.each {|x| do_something(x)}

Again, I didn’t think too much about this as I wrote that code – I
just wanted to iterate over the data I had accumulated. Later, when I
realized that I wanted to index into my data by it’s name, I thought,
“Gee, this is Ruby – I should be able to just change that to a hash
and be able to do that. I don’t care about the index anywhere in my
code.” But I realized (immediately) that Hash#each didn’t do the same
thing as Array#each. (Fortunately, my code base was small and trivial
enough, that I could change #each to #each_value, but it made me
wonder what I should have done differently to begin with, and how I
would have handled this case if the code base weren’t so small and
trivial.)

With that long winded setup… here is the next question I promised
you…

What do other folks do in this situation?

Are you all just smarter/more experienced with Ruby/ than I am and
have learned (perhaps through bitter experience) that storing things
in a Hash is better than storing them in an array when you are just
prototyping some code, not knowing where it will eventually lead? Do
you all know of the secret Array#each_element iterator which does the
same thing as the Hash#each_element iterator and you just use that?

On a related note…
Would it make sense to propose adding an Array#each_value, aliased to
Array#each to the baseline language/library definition so that one
could use the same iterator independent of whether the underlying
container were a Hash or an Array? Would it make sense to propose
adding an #each_element iterator to both classes?

–wpd

#11

On Tue, Aug 19, 2008 at 1:08 AM, Patrick D. removed_email_address@domain.invalid
wrote:

dataset.each {|x| do_something(x)}

fixing it is as simple as this (if you don’t wanna change the method):
dataset.each{|key, x| do_something(x)}

also, informing you about the places where you call #each while still
providing the behaviour you want without changing the block arguments:

def dataset.each
puts “dataset.each was called from:”, *caller

super do |key, value|
yield value
end
end

And no, i don’t think Hash should behave like Array, sometimes i’d
want Array to behave more like Hash though :slight_smile:

^ manveru