How to sort an alphanumeric array in ruby
You can pass a block to the sort function to custom sort it. In your case you will have a problem because your numbers aren't zero padded, so this method zero pads the numerical parts, then sorts them, resulting in your desired sort order.
a.sort { |a,b|
ap = a.split('_')
a = ap[0] + "%05d" % ap[1] + "%05d" % ap[2]
bp = b.split('_')
b = bp[0] + "%05d" % bp[1] + "%05d" % bp[2]
b <=> a
}
ruby alphanumeric sort not working as expected
You are sorting strings. Strings are sorted like strings, not like numbers. If you want to sort like numbers, then you should sort numbers, not strings. The string 'B10'
is lexicographically smaller than the string 'B3'
, that's not something unique to Ruby, that's not even something unique to programming, that's how lexicographically sorting a piece of text works pretty much everywhere, in programming, databases, lexicons, dictionaries, phonebooks, etc.
You should split your strings into their numerical and non-numerical components, and convert the numerical components to numbers. Array sorting is lexicographic, so this will end up sorting exactly right:
y.sort_by {|s| # use `sort_by` for a keyed sort, not `sort`
s.
split(/(\d+)/). # split numeric parts from non-numeric
map {|s| # the below parses numeric parts as decimals, ignores the rest
begin Integer(s, 10); rescue ArgumentError; s end }}
#=> ["A1", "A2", "A6", "A8", "B3", "B4", "B5", "B8", "B10", "B12"]
Sorting ruby array as alphanumeric
Lets say you have an array:
a = ["site.com?page=7", "site.com?page=8", "site.com?page=9", "site.com?page=880"]
Then you can do:
a = a.sort_by{|t| t.split(/page=/)[1].to_i}
In short I use a custom sort criteria and that criteria is to split the string by "page=", then use the numerical value(to_i
) of the string after the first match of page=
for the sorting.
Why does ruby sort Alphanumeric strings with 1's and 0's as binary?
If your array were
arr = ["Q10", "Q100", "Q1000", "Q8", "Q1001", "Q98"]
you could write
arr.sort_by { |s| s[/\d+/].to_i }
#=> ["Q8", "Q10", "Q98", "Q100", "Q1000", "Q1001"]
If
s = "Q1000"
then
s[/\d+/].to_i
#=> 1000
See Enumerable#sort_by and String#[].
The regular expression /\d+/
matches a substring of s
that contains one or more digits.
If the array were
arr = ["Q10b", "Q100", "Q1000", "Q10a", "Q1001", "Q98", "Q10c"]
you could write
arr.sort_by { |s| [s[/\d+/].to_i, s[/\D+\z/]] }
#=> ["Q10a", "Q10b", "Q10c", "Q98", "Q100", "Q1000", "Q1001"]
If
s = "Q10b"
then
[s[/\d+/].to_i, s[/\D+\z/]]
#=> [10, "b"]
The regular expression /\D+\z/
matches a substring of s
that contains one or more non-digits at the end (\z
) of the string.
See Array#<=>, specifically the third paragraph, for an explanation of how arrays are ordered when sorting.
If the array were
arr = ["Q10b", "P100", "Q1000", "PQ10a", "Q1001", "Q98", "Q10c"]
you could write
arr.sort_by { |s| [s[/\A\D+/], s[/\d+/].to_i, s[/\D+\z/]] }
#=> ["P100", "PQ10a", "Q10b", "Q10c", "Q98", "Q1000", "Q1001"]
If
s = "PQ10a"
then
[s[/\A\D+/], s[/\d+/].to_i, s[/\D+\z/]]
#=> ["PQ", 10, "a"]
The regular expression /\A\D+/
matches a substring of s
that contains one or more non-digits at the beginning (\A
) of the string.
How to sort an array of strings containing numbers and letters in ruby
array.sort_by { |item|
number, letter = *item.split
[letter, number.to_i]
}
Arrays compare as their first element; in case an element is equal, next element is compared.
How to sort array of string by alphabetical order with domain based list
You where on the correct path with array.sort_by{|x|x.split('.').last}
. The problem is that you now only sort by the last domain part and not the underlying sub-domains. Instead reverse
the split
result so it first sorts by "com"
, then "ramo"
followed by other the sub-domains.
array = ["test-new.ramo.com", "analytics.ramo.com", "top-test.ramo.com", "ec2.new.ramo.com", "ccc.ramo.com", "ddd.kumar.ramo.com", "ccc.test.ramo", "ramo.com"]
array.sort_by { |domain| domain.split('.').reverse }
#=> ["ramo.com",
# "analytics.ramo.com",
# "ccc.ramo.com",
# "ddd.kumar.ramo.com",
# "ec2.new.ramo.com",
# "test-new.ramo.com",
# "top-test.ramo.com",
# "ccc.test.ramo"]
This sorts the domains first based on the last part, then the second-last part etc.
The reason "ddd.kumar.ramo.com"
is out of order compared with your expectation is because "kumar" > "ccc"
and "kumar" < "new"
. The same applies for "ec2.new.ramo.com"
. If you want them in the exact same positions as specified in the question you need to sort by domain part count first.
array.sort_by do |domain|
parts = domain.split('.').reverse
parts.unshift(parts.count)
end
#=> ["ramo.com",
# "analytics.ramo.com",
# "ccc.ramo.com",
# "test-new.ramo.com",
# "top-test.ramo.com",
# "ccc.test.ramo",
# "ddd.kumar.ramo.com",
# "ec2.new.ramo.com"]
Related Topics
How to Convert Character Code to What I Want
Return Values Were Not Extracted in Ruby
Update Field Through Link_To in Rails
How to Serialize a Ruby Digest::Sha1 Instance Object
Ruby: Automatically Wrapping Methods in Event Triggers
How to Get Repeated Elements from Ruby Array
Rails: Chartkick Cummulative User Graph
Parsing Uris That Have Curly Braces, Uri::Invalidurierror: Bad Uri(Is Not Uri)
Mini_Magick Gem Doesn't Work with My Imagemagick Install
Get List Timeline by Using Twitter Gem
Integrate Shoes into Aptana Studio Radrails
How to Distribute a Ruby Script via Homebrew
How to Reset Boolean to "Default: False" at End of Day
How Does This Block Work for Integer Times Method
What's a Semantically-Correct Way to Parse CSV from SQL Server 2008
How to Stop Chromedriver from Opening Settings Tab Automatically