Grehom wrote:
what am I doing wrong? I wanted to sort primarily on count (second
position in array), then sub-sort alphabetically (first position in
array)
char_freq = [["c", 2],["b", 5],["a", 2]]
sorted_freq = char_freq.sort {|a, b| b[1]<=>a[1] || a[0]<=>b[0] }
sorted_freq.each do |d|
print d[0]*d[1]
end
produces >> bbbbbccaa
when I was rather hoping for >> bbbbbaacc
I tried using brackets and using 'or' instead of '||' even tried the
sort_by method, any help much appreciated I know this works in perl
(add 13 dollar signs, etc and shake well!):
use strict;
use warnings;
my @char_freq = (["c", 2], ["b", 5], ["a", 2]);
foreach my $d (sort {$$b[1] <=> $$a[1] || $$a[0] cmp $$b[0] }
@char_freq) {
print $$d[0] x $$d[1]
}
produces >> bbbbbaacc
Generally you need to do conditional evaluation based on higher prio
results. Using "||" or "or" won't help here (dunno what Perl does here).
You want something like
char_freq = [["c", 2],["b", 5],["a", 2]]
sorted_freq = char_freq.sort do |a, b|
c = b[1]<=>a[1]
c == 0 ? a[0]<=>b[0] : c
end
sorted_freq.each do |d|
print d[0]*d[1]
end
You can make your life easier (though less efficient) with a helper:
def multi_compare(*results)
results.each {|c| return c if c != 0}
0
end
char_freq = [["c", 2],["b", 5],["a", 2]]
sorted_freq = char_freq.sort {|a,b| multi_compare(b[1]<=>a[1],
a[0]<=>b[0])}
sorted_freq.map {|a,b| a*b}.join
char_freq = [["c", 2],["b", 5],["a", 2]]
=> [["c", 2], ["b", 5], ["a", 2]]
sorted_freq = char_freq.sort {|a,b| multi_compare(b[1]<=>a[1],
a[0]<=>b[0])}
=> [["b", 5], ["a", 2], ["c", 2]]
sorted_freq.map {|a,b| a*b}.join
=> "bbbbbaacc"
You can also do something like this which avoids evaluation of all
conditions:
class Integer
# condition chain
def cc()
self == 0 ? yield : self
end
end
char_freq = [["c", 2],["b", 5],["a", 2]]
sorted_freq = char_freq.sort {|a,b| (b[1]<=>a[1]).cc { a[0]<=>b[0] }}
sorted_freq.map {|a,b| a*b}.join
char_freq.sort {|a,b| (b[1]<=>a[1]).cc { a[0]<=>b[0] }}.map {|a,b|
a*b}.join
=> "bbbbbaacc"
HTH
Kind regards
robert