[Nuby] Sorting a Hash and keepint it as a Hash?

W

Williams, Chris

------_=_NextPart_001_01C4E14F.4AE3BE3B
Content-Type: text/plain;
charset="us-ascii"
Content-Transfer-Encoding: quoted-printable

Another nuby question:

I have a Hash of objects which I want to sort by the values. Afterwards
I want to pull out the keys as one array and the values as another. So I
have code like so:

# sort by frequency ascending
@fault_sums =3D @fault_sums.sort {|a,b| a[1] <=3D> b[1]}
# Only keep top N
@fault_sums.slice!(0...-@number) if @number <=3D @fault_sums.size=20
=20
fields =3D @fault_sums.keys
data =3D @fault_sums.values

But when I get to calling keys and values on the Hash I realized, sort
actually returns back a 2D array and those methods aren't defined on an
Array. Is there a way to make the 2D Array returned by the sort back
into a Hash?

Thanks,
Chris Williams

------_=_NextPart_001_01C4E14F.4AE3BE3B--
 
L

Logan Capaldo

Another nuby question:

I have a Hash of objects which I want to sort by the values. Afterwards
I want to pull out the keys as one array and the values as another. So I
have code like so:

# sort by frequency ascending
@fault_sums = @fault_sums.sort {|a,b| a[1] <=> b[1]}
# Only keep top N
@fault_sums.slice!(0...-@number) if @number <= @fault_sums.size

fields = @fault_sums.keys
data = @fault_sums.values

But when I get to calling keys and values on the Hash I realized, sort
actually returns back a 2D array and those methods aren't defined on an
Array. Is there a way to make the 2D Array returned by the sort back
into a Hash?

Thanks,
Chris Williams
Well you could but you'd be back at square one since a hash is
unordered. An alternate method is to sort the keys by the values, ie

keys_ordered = some_hash.keys.sort { |a, b| some_hash[a] <=> some_hash }

keys_ordered.each { |k|
# do something with some_hash[k]
}

Of course you'll have to change it to fit exactly what you need.
 
R

Robert Klemme

Another nuby question:

I have a Hash of objects which I want to sort by the values. Afterwards
I want to pull out the keys as one array and the values as another. So I
have code like so:

You want sort with a block:
=> [[1, "a"], [2, "b"]]

If you use inject you can get your two arrays in one go:
h.sort {|(k1,v1),(k2,v2)| v1 <=> v2}.inject([[],[]]) {|(ks,vs),(k,v)| ks
<< k; vs << v; [ks,vs]} => [[1, 2], ["a", "b"]]
keys, values = h.sort {|(k1,v1),(k2,v2)| v1 <=> v2}.inject([[],[]])
{|(ks,vs),(k,v)| ks << k; vs << v; [ks,vs]} => [[1, 2], ["a", "b"]]
keys => [1, 2]
values
=> ["a", "b"]
# sort by frequency ascending
@fault_sums = @fault_sums.sort {|a,b| a[1] <=> b[1]}
# Only keep top N
@fault_sums.slice!(0...-@number) if @number <= @fault_sums.size

fields = @fault_sums.keys
data = @fault_sums.values

But when I get to calling keys and values on the Hash I realized, sort
actually returns back a 2D array and those methods aren't defined on an
Array. Is there a way to make the 2D Array returned by the sort back
into a Hash?

This won't help as the hash you get then is unsorted again. If you need a
copy, Hash#dup or Marshal.load(Marshal.dump(hash)) is a better choice.

Kind regards

robert
 
F

Florian Gross

I have a Hash of objects which I want to sort by the values. Afterwards
I want to pull out the keys as one array and the values as another. So I
have code like so:

# sort by frequency ascending
@fault_sums = @fault_sums.sort {|a,b| a[1] <=> b[1]}
# Only keep top N
@fault_sums.slice!(0...-@number) if @number <= @fault_sums.size

fields = @fault_sums.keys
data = @fault_sums.values

But when I get to calling keys and values on the Hash I realized, sort
actually returns back a 2D array and those methods aren't defined on an
Array. Is there a way to make the 2D Array returned by the sort back
into a Hash?

There's no sorted Hashs in Standard Ruby so you will get a sorted Array
of pairs.

However you can use a nifty trick to get the keys and values out of that:

[['key1', 'value1'], ['key2', 'value2']].transpose
# => [['key1', 'key2'], ['value1', 'value2']]

So this will solve your problem:

top_pairs = @faults_sum.sort_by { |key, value| -value }.first(@number)
fields, data = *top_pairs.transpose

Note that I chose to sort descending and to keep the first (high sum)
entries instead of sorting ascending and to keep the lowest (high sum)
entries in reverse.
 

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

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,121
Latest member
LowellMcGu
Top