Hash with Integer key issue

Hi Im new to Ruby and am getting some unexpected results from a
dynamically created Hash. The following from irb is my attempt to
troubleshoot why its not working.

irb(main):028:0> x = Hash.new
=> {}

# Dynamically build the hash, works.
irb(main):029:0> (1..49).each { |y| x[y] = y-2 }
=> 1..49

irb(main):030:0> x
=> {1=>-1, 2=>0, 3=>1, 4=>2, 5=>3, 6=>4, 7=>5, 8=>6, 9=>7, 10=>8, 11=>9,
12=>10, 13=>11, 14=>12, 15=>13, 16=>14, 17=>15, 18=>16, 19=>17, 20=>18,
21=>19, 22=>20, 23=>21, 24=>22, 25=>23, 26=>24, 27=>25, 28=>26, 29=>27,
30=>28, 31=>29, 32=>30, 33=>31, 34=>32, 35=>33, 36=>34, 37=>35, 38=>36,
39=>37, 40=>38, 41=>39, 42=>40, 43=>41, 44=>42, 45=>43, 46=>44, 47=>45,
48=>46, 49=>47}

# Gives the result I expect
irb(main):031:0> x[46]
=> 44

# Sort by the value...
irb(main):032:0> x = x.sort_by {|k,v| v}.reverse
=> [[49, 47], [48, 46], [47, 45], [46, 44], [45, 43], [44, 42], [43,
41], [42, 40], [41, 39], [40, 38], [39, 37], [38, 36], [37, 35], [36,
34], [35, 33], [34, 32], [33, 31], [32, 30], [31, 29], [30, 28], [29,
27], [28, 26], [27, 25], [26, 24], [25, 23], [24, 22], [23, 21], [22,
20], [21, 19], [20, 18], [19, 17], [18, 16], [17, 15], [16, 14], [15,
13], [14, 12], [13, 11], [12, 10], [11, 9], [10, 8], [9, 7], [8, 6], [7,
5], [6, 4], [5, 3], [4, 2], [3, 1], [2, 0], [1, -1]]

# And here is the problem! Now that I am looking at it here, it's
obvious that the sort is flattening the Hash... Is there a way to
restore it to a Hash, or a better way to achieve the sort?

irb(main):033:0> x[46]
=> [3, 1]

I'm sure I'm over looking something simple. Please help, I need the
sorted Hash to give me the appropriate value for the Integer key...

···

--
Posted via http://www.ruby-forum.com/.

Sorting the hash creates a nested "array" which you assigned back to x.
If you type check x, it is now an array.

S

Excerpts from Wayne Simmerson's message of 2012-10-19 19:12:16 -0400:

···

Hi Im new to Ruby and am getting some unexpected results from a
dynamically created Hash. The following from irb is my attempt to
troubleshoot why its not working.

irb(main):028:0> x = Hash.new
=> {}

# Dynamically build the hash, works.
irb(main):029:0> (1..49).each { |y| x[y] = y-2 }
=> 1..49

irb(main):030:0> x
=> {1=>-1, 2=>0, 3=>1, 4=>2, 5=>3, 6=>4, 7=>5, 8=>6, 9=>7, 10=>8, 11=>9,
12=>10, 13=>11, 14=>12, 15=>13, 16=>14, 17=>15, 18=>16, 19=>17, 20=>18,
21=>19, 22=>20, 23=>21, 24=>22, 25=>23, 26=>24, 27=>25, 28=>26, 29=>27,
30=>28, 31=>29, 32=>30, 33=>31, 34=>32, 35=>33, 36=>34, 37=>35, 38=>36,
39=>37, 40=>38, 41=>39, 42=>40, 43=>41, 44=>42, 45=>43, 46=>44, 47=>45,
48=>46, 49=>47}

# Gives the result I expect
irb(main):031:0> x[46]
=> 44

# Sort by the value...
irb(main):032:0> x = x.sort_by {|k,v| v}.reverse
=> [[49, 47], [48, 46], [47, 45], [46, 44], [45, 43], [44, 42], [43,
41], [42, 40], [41, 39], [40, 38], [39, 37], [38, 36], [37, 35], [36,
34], [35, 33], [34, 32], [33, 31], [32, 30], [31, 29], [30, 28], [29,
27], [28, 26], [27, 25], [26, 24], [25, 23], [24, 22], [23, 21], [22,
20], [21, 19], [20, 18], [19, 17], [18, 16], [17, 15], [16, 14], [15,
13], [14, 12], [13, 11], [12, 10], [11, 9], [10, 8], [9, 7], [8, 6], [7,
5], [6, 4], [5, 3], [4, 2], [3, 1], [2, 0], [1, -1]]

# And here is the problem! Now that I am looking at it here, it's
obvious that the sort is flattening the Hash... Is there a way to
restore it to a Hash, or a better way to achieve the sort?

irb(main):033:0> x[46]
=> [3, 1]

I'm sure I'm over looking something simple. Please help, I need the
sorted Hash to give me the appropriate value for the Integer key...

--
"Truth or die."

Steven Hum
5 - 28 Gilmour St
Ottawa, ON K2P 0N3
email sdothum@gmail.com
tel 613.237.9058

# And here is the problem! Now that I am looking at it here, it's
obvious that the sort is flattening the Hash... Is there a way to
restore it to a Hash, or a better way to achieve the sort?

irb(main):033:0> x[46]
=> [3, 1]

Does this help?

arr = [[49, 47], [48, 46], [47, 45], [46, 44], [45, 43], [44, 42]]
p Hash[*arr.flatten]

#> {49=>47, 48=>46, 47=>45, 46=>44, 45=>43, 44=>42}

Harry

Wayne Simmerson wrote in post #1080492:

# And here is the problem! Now that I am looking at it here, it's
obvious that the sort is flattening the Hash... Is there a way to
restore it to a Hash, or a better way to achieve the sort?

Hi,

the standard "sort" method always returns an array of the objects coming
from the "each" method. It does *not* return the original data
structure. In other words: Whatever you sort, you always get back a
sorted array.

This usually works fine, because most of the time you just want to have
the elements in a specific order. If you actually need to retain the
original data structure, you have to rebuild the object from the array
(as Harry and Arlen demonstrated).

In this case, however, I think it's in fact a misunderstanding of
hashes. The idea of a hash is to map keys to values. It doesn't have an
inner order(*). So you might want to rethink if this is the right data
structure for your purpose. Maybe you just want an array?

(*)
In newer versions of Ruby, hashes actually do have an inner order
(probably to be less surprising to newbies). So they're really a hybrid
of a hash an an array. However, I still wouldn't use them as an ordered
sequence of elements but to map keys to values.

···

--
Posted via http://www.ruby-forum.com/\.

# And here is the problem! Now that I am looking at it here, it's
obvious that the sort is flattening the Hash... Is there a way to
restore it to a Hash, or a better way to achieve the sort?

Or you could generate it like this. It depends on what you are trying to do.

x = Hash.new
49.downto(1).each { |y| x[y] = y-2 }
p x

Harry

Thanks for all the replies, I actually figured it out about 2 minutes
after I posted the question. I was banging my head against my desk for
hours trying to figure out why it wasn't working, completely oblivious
to the fact it had been converted to an Array. It took writing it out
here to notice the Hash had been Arrayed!

Is there no way to sort the hash and convert it back in the same
statement? Would be nice to do in a single line of code.

···

--
Posted via http://www.ruby-forum.com/.

Why does every single thread in this forum turn into an endless expert
discussion about terms or technical details?

All the OP wanted to know is how to sort a hash. Harry showed him, and I
made a remark that a hash might not be the best way to represent a
sequence of numbers, even though it can be used that way in newer
versions of Ruby. Can't we just leave it at that?

···

--
Posted via http://www.ruby-forum.com/.

Note that "Hash[arr]" works too!

···

On Saturday, 20 October 2012 at 2:27 PM, Harry Kakueki wrote:

> # And here is the problem! Now that I am looking at it here, it's
> obvious that the sort is flattening the Hash... Is there a way to
> restore it to a Hash, or a better way to achieve the sort?
>
> irb(main):033:0> x[46]
> => [3, 1]

Does this help?

arr = [[49, 47], [48, 46], [47, 45], [46, 44], [45, 43], [44, 42]]
p Hash[*arr.flatten]

#> {49=>47, 48=>46, 47=>45, 46=>44, 45=>43, 44=>42}

Harry

Or you could generate it like this. It depends on what you are trying to do.

x = Hash.new
49.downto(1).each { |y| x[y] = y-2 }
p x

Actually, you do not need the #each.

x = Hash.new
49.downto(1) {|y| x[y] = y-2}
p x

Harry

Arlen already told you!

   new_hash = Hash[x.sort_by {|k,v| v }.reverse]

But I do not see the use case for a sorted hash,
it appears conceptually wrong to me. Have you read Jan's post?

···

Am 20.10.2012 14:46, schrieb Wayne Simmerson:

Thanks for all the replies, I actually figured it out about 2 minutes
after I posted the question. I was banging my head against my desk for
hours trying to figure out why it wasn't working, completely oblivious
to the fact it had been converted to an Array. It took writing it out
here to notice the Hash had been Arrayed!

Is there no way to sort the hash and convert it back in the same
statement? Would be nice to do in a single line of code.

--
<https://github.com/stomar/&gt;

+1

···

Am 21.10.2012 15:33, schrieb Jan E.:

Why does every single thread in this forum turn into an endless expert
discussion about terms or technical details?

--
<https://github.com/stomar/&gt;

Because if you misunderstand the terms or technical details then you won't understand why things don't work as you expect, eg. why sorting a hash returns an array,

or calling a hash sorted vs ordered will raise more questions than it answers.

Teaching people technical details will help them figure things out for themselves.

Henry

···

On 22/10/2012, at 2:33 AM, "Jan E." <lists@ruby-forum.com> wrote:

Why does every single thread in this forum turn into an endless expert
discussion about terms or technical details?

unknown wrote in post #1080532:

···

Am 20.10.2012 14:46, schrieb Wayne Simmerson:

Thanks for all the replies, I actually figured it out about 2 minutes
after I posted the question. I was banging my head against my desk for
hours trying to figure out why it wasn't working, completely oblivious
to the fact it had been converted to an Array. It took writing it out
here to notice the Hash had been Arrayed!

Is there no way to sort the hash and convert it back in the same
statement? Would be nice to do in a single line of code.

Arlen already told you!

   new_hash = Hash[x.sort_by {|k,v| v }.reverse]

But I do not see the use case for a sorted hash,
it appears conceptually wrong to me. Have you read Jan's post?

If you believe Hashes are unsorted, then why would you reverse an array
before converting it to a Hash?

--
Posted via http://www.ruby-forum.com/\.

But dissecting each word of every fast answer to some simple question
and dragging on and on might turn off contributors from this list.

···

Am 22.10.2012 01:19, schrieb Henry Maddocks:

On 22/10/2012, at 2:33 AM, "Jan E." <lists@ruby-forum.com> wrote:

Why does every single thread in this forum turn into an endless expert
discussion about terms or technical details?

Because if you misunderstand the terms or technical details then you won't understand why things don't work as you expect, eg. why sorting a hash returns an array,

or calling a hash sorted vs ordered will raise more questions than it answers.

Teaching people technical details will help them figure things out for themselves.

Henry

--
<https://github.com/stomar/&gt;

Hashes are unsorted. However, in Ruby 1.9 (but not in 1.8) they are
ordered; that is, when you iterate over them, the elements are yielded
in the same order as they were inserted.

-- Matma Rex

Have you read the previous posts in this thread?
The code above was given in reply to the OP's question, and it works
as expected in Ruby 1.9.3 because hashes are indeed sorted there.
(It probably should have been mentioned that it fails in Ruby 1.8).

What I did want to point out is that I do not see why a hash is used
here, when order seems to be crucial to the OP's purposes.

···

Am 20.10.2012 18:23, schrieb 7stud --:

Arlen already told you!

    new_hash = Hash[x.sort_by {|k,v| v }.reverse]

But I do not see the use case for a sorted hash,
it appears conceptually wrong to me. Have you read Jan's post?

If you believe Hashes are unsorted, then why would you reverse an array
before converting it to a Hash?

--
<https://github.com/stomar/&gt;

unknown wrote in post #1080538:

Have you read the previous posts in this thread?
The code above was given in reply to the OP's question, and it works
as expected in Ruby 1.9.3 because hashes are indeed sorted there.

FWIW, they are not sorted, but they do retain the original insertion
order.

If you want a collection which is always sorted, then you need something
like a heap.

···

--
Posted via http://www.ruby-forum.com/\.

unknown wrote in post #1080538:

Have you read the previous posts in this thread?
The code above was given in reply to the OP's question, and it works
as expected in Ruby 1.9.3 because hashes are indeed sorted there.

FWIW, they are not sorted, but they do retain the original insertion
order.

That's hair splitting...
one can say they are sorted by insertion order,
and in the considered example only that matters.

If you want a collection which is always sorted, then you need something
like a heap.

Sigh... that's exactly my point, All I wanted to convey to the OP
is that he most probably should *not* use a hash here.

Maybe the problem here is that I'm not a native speaker.

···

Am 21.10.2012 14:33, schrieb Brian Candler:

--
<https://github.com/stomar/&gt;