enigma
enigma

Reputation: 91

How to sort text by numeric order in ruby table

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

Answers (2)

Cary Swoveland
Cary Swoveland

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

the Tin Man
the Tin Man

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

Related Questions