How to Sort an Alphanumeric Array in Ruby

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



Leave a reply



Submit