Reputation: 91
I'm trying to sort this text with Ruby but it does not work.
1,fgff
12,seffdd
2,dssffs
Using:
cat sorting | ruby -ne 'BEGIN{ $x=[]}; $x << $_.chomp.to_s; END { puts $x.sort }'
I get this result:
1,fgff
12,seffdd
2,dssffs
I expected this
1,fgff
2,dssffs
12,seffdd
How woudld I fix my code?
Upvotes: 1
Views: 229
Reputation: 110675
If there may be duplicates of the numeric part of the string, and the rest of the string is to be used to break ties, you can do the following.
str =<<END
1,fgff
12,seffdd
12,seffda
2,dssffs
END
str.lines.sort_by do |s|
n, t = s.split(',')
[n.to_i, t]
end
#=> ["1,fgff\n", "2,dssffs\n", "12,seffda\n", "12,seffdd\n"]
See Array#<=> for an explanation of how arrays are ordered.
Upvotes: 1
Reputation: 160551
The problem is you're not sorting numerically, you are sorting by character values:
[1, 12, 2].sort # => [1, 2, 12]
%w[1 12 2].sort # => ["1", "12", "2"]
Instead:
str = <<EOT
1,fgff
12,seffdd
2,dssffs
EOT
str.lines.sort_by { |l| l.to_i }.join
# => "1,fgff\n" +
# "2,dssffs\n" +
# "12,seffdd\n"
to_i
will return the integer value of the string, up to the first non-digit:
'1'.to_i # => 1
'1 2'.to_i # => 1
'1,2'.to_i # => 1
'1_2'.to_i # => 12
The final one succeeds, because Ruby, like many other languages, allows the use of underscore (_
) as a separator, similar to how we use comma:
1000 # => 1000
1_000 # => 1000
Knowing that:
'1,fgff'.to_i # => 1
'12,seffdd'.to_i # => 12
'2,dssffs'.to_i # => 2
It'd also be useful to read about the difference between sort
and sort_by
. There are major speedups available using the proper one, given the right programming situation.
Upvotes: 6