Sanjay
Sanjay

Reputation: 382

How to sort of string array

I am working on ruby on rails and i am new here as well ruby on rails. I am working on one project and find some issue of sorting an array of string which contains images name. I have tried many algorithm which i know doesn't help me. When i call service for image extraction it gives me like this array.

Example:

["page-1_1.png",
 "page-1_10.png",
 "page-1_11.png",
 "page-1_2.png",
 "page-1_3.png",
 "page-1_4.png",
 "page-1_5.png",
 "page-1_6.png",
 "page-1_7.png",
 "page-1_8.png",
 "page-1_9.png"]

I want to sort this array like this:

["page-1_1.png",
 "page-1_2.png",
 "page-1_3.png",
 "page-1_4.png",
 "page-1_5.png",
 "page-1_6.png",
 "page-1_7.png",
 "page-1_8.png",
 "page-1_9.png",
 "page-1_10.png",
 "page-1_11.png"]

I had tried many things to sort but can't get any solutions. please help me.

Upvotes: 3

Views: 494

Answers (3)

ndnenkov
ndnenkov

Reputation: 36110

names.sort_by { |name| name.scan(/\d+/).map(&:to_i) }

This finds all numbers in each file name and sorts by said numbers. Note that arrays are ordered by comparing the first element, in case of equality - the second and so on.

Upvotes: 10

Cary Swoveland
Cary Swoveland

Reputation: 110755

For the given array, arr, here's an off-the-wall solution.

require 'ipaddr'

arr.sort_by { |s| IPAddr.new(s.gsub(/\D/) { |c| c == '_' ? '.' : '' } + '.0.0') }
  #=> ["page-1_1.png",
  #    "page-1_2.png",
  #    "page-1_3.png",
  #    "page-1_4.png",
  #    "page-1_5.png",
  #    "page-1_6.png",
  #    "page-1_7.png",
  #    "page-1_10.png",
  #    "page-1_11.png",
  #    "page-3_92.png",
  #    "page-11_8.png"] 

Note that

arr.map { |s| IPAddr.new(s.gsub(/\D/) { |c| c == '_' ? '.' : '' } + '.0.0') }
  #=> [#<IPAddr: IPv4:1.1.0.0/255.255.255.255>,
  #    #<IPAddr: IPv4:1.10.0.0/255.255.255.255>,
  #    #<IPAddr: IPv4:1.11.0.0/255.255.255.255>,
  #    #<IPAddr: IPv4:1.2.0.0/255.255.255.255>,
  #    #<IPAddr: IPv4:1.3.0.0/255.255.255.255>,
  #    #<IPAddr: IPv4:1.4.0.0/255.255.255.255>,
  #    #<IPAddr: IPv4:1.5.0.0/255.255.255.255>,
  #    #<IPAddr: IPv4:1.6.0.0/255.255.255.255>,
  #    #<IPAddr: IPv4:1.7.0.0/255.255.255.255>,
  #    #<IPAddr: IPv4:11.8.0.0/255.255.255.255>,
  #    #<IPAddr: IPv4:3.92.0.0/255.255.255.255>] 

Upvotes: 2

Eric Duminil
Eric Duminil

Reputation: 54303

If you know that the number of pages is bounded (e.g. less than 1000), this method has the advantage of sorting alphabetically and numerically :

arr =
  ['page-1_1.png',
   'page-1_10.png',
   'page-1_11.png',
   'page-1_3.png',
   'page-1_9.png']

puts arr.sort_by{ |str| str.gsub(/\d+/){ |number| number.rjust(3, '0') } }
# page-1_1.png
# page-1_3.png
# page-1_9.png
# page-1_10.png
# page-1_11.png

puts %w(b c a).sort_by{ |str| str.gsub(/\d+/){ |number| number.rjust(3, '0') } }
# a
# b
# c

Here are the temporary strings that are being sorted :

puts arr.map{ |str| str.gsub(/\d+/){ |number| number.rjust(3, '0') } }
# page-001_001.png
# page-001_010.png
# page-001_011.png
# page-001_003.png
# page-001_009.png

Upvotes: 2

Related Questions