Professional Web Applications Themes

Natural order sort - Ruby

I've written a natural order comparison funtion for the String class. This was based on Martin Pool's "Natural Order String Comparison" which was written in C. [url]http://sourcefrog.net/projects/natsort/[/url] The basic premise is that "something1" < "something2" < "something10" which does not follow if you use alphabetical sorting. I thought I'd post it here in case anyone was interested in it. I'd also be grateful of any comments about improving it in any way. class String # 'Natural order' comparison of two strings def String.natcmp(str1, str2, caseInsensitive=false) str1, str2 = str1.dup, str2.dup compareExpression = /^(\D*)(\d*)(.*)$/ if caseInsensitive str1.downcase! str2.downcase! end # Remove ...

  1. #1

    Default Natural order sort

    I've written a natural order comparison funtion for the String class.
    This was based on Martin Pool's "Natural Order String Comparison" which
    was written in C.
    [url]http://sourcefrog.net/projects/natsort/[/url]

    The basic premise is that "something1" < "something2" < "something10"
    which does not follow if you use alphabetical sorting.

    I thought I'd post it here in case anyone was interested in it. I'd
    also be grateful of any comments about improving it in any way.

    class String

    # 'Natural order' comparison of two strings
    def String.natcmp(str1, str2, caseInsensitive=false)
    str1, str2 = str1.dup, str2.dup
    compareExpression = /^(\D*)(\d*)(.*)$/

    if caseInsensitive
    str1.downcase!
    str2.downcase!
    end

    # Remove all whitespace
    str1.gsub!(/\s*/, '')
    str2.gsub!(/\s*/, '')

    while (str1.length > 0) or (str2.length > 0) do
    # Extract non-digits, digits and rest of string
    str1 =~ compareExpression
    chars1, num1, str1 = $1.dup, $2.dup, $3.dup

    str2 =~ compareExpression
    chars2, num2, str2 = $1.dup, $2.dup, $3.dup

    # Compare the non-digits
    case (chars1 <=> chars2)
    when 0 # Non-digits are the same, compare the digits...
    # If either number begins with a zero, then compare
    # alphabetically, otherwise compare numerically
    if (num1[0] != 48) and (num2[0] != 48)
    num1, num2 = num1.to_i, num2.to_i
    end

    case (num1 <=> num2)
    when -1 then return -1
    when 1 then return 1
    end
    when -1 then return -1
    when 1 then return 1
    end # case

    end # while

    # Strings are naturally equal
    return 0
    end

    end # class String

    puts [ "something1", "12", "something10", "something2" ].sort { |a,b|
    String.natcmp(a,b)
    }


    RESULT:

    12
    something1
    something2
    something10



    Alan Davies Guest

  2. #2

    Default Re: Natural order sort

    Alan Davies <NOSPAMcs96andyahoo.co.ukNOSPAM> wrote:
    > I've written a natural order comparison funtion for the String class.
    > This was based on Martin Pool's "Natural Order String Comparison" which
    > was written in C.
    > [url]http://sourcefrog.net/projects/natsort/[/url]
    >
    > The basic premise is that "something1" < "something2" < "something10"
    > which does not follow if you use alphabetical sorting.
    >
    > I thought I'd post it here in case anyone was interested in it. I'd
    > also be grateful of any comments about improving it in any way.
    Nifty and new in Ruby 1.8 is #sort_by:

    def String.natural_order(nocase=false)
    proc do |str|
    i = true
    str = str.upcase if nocase
    str.gsub(/\s+/, '').split(/(\d+)/).map {|x| (i = !i) ? x.to_i : x}
    end
    end

    puts %w[ foo1 12 foo10 foo2 ].sort_by(&String.natural_order)
    Sabby and Tabby Guest

  3. #3

    Default Re: Natural order sort

    >>split(/(\d+)/)

    Interesting. I always assumed split filtered out the matching sections,
    but it appears that you can make them appear in the resulting array by
    putting brackets round the relevant bit in the regexp.

    This isn't mentioned in the Pragmatic Programmers book.


    Sabby and Tabby wrote:
    > Alan Davies <NOSPAMcs96andyahoo.co.ukNOSPAM> wrote:
    >
    >
    >>I've written a natural order comparison funtion for the String class.
    >>This was based on Martin Pool's "Natural Order String Comparison" which
    >>was written in C.
    >>[url]http://sourcefrog.net/projects/natsort/[/url]
    >>
    >>The basic premise is that "something1" < "something2" < "something10"
    >>which does not follow if you use alphabetical sorting.
    >>
    >>I thought I'd post it here in case anyone was interested in it. I'd
    >>also be grateful of any comments about improving it in any way.
    >
    >
    > Nifty and new in Ruby 1.8 is #sort_by:
    >
    > def String.natural_order(nocase=false)
    > proc do |str|
    > i = true
    > str = str.upcase if nocase
    > str.gsub(/\s+/, '').split(/(\d+)/).map {|x| (i = !i) ? x.to_i : x}
    > end
    > end
    >
    > puts %w[ foo1 12 foo10 foo2 ].sort_by(&String.natural_order)
    Alan Davies Guest

  4. #4

    Default Re: Natural order sort


    On Monday, September 15, 2003, at 12:07 PM, Alan Davies wrote:
    > Interesting. I always assumed split filtered out the matching
    > sections, but it appears that you can make them appear in the
    > resulting array by putting brackets round the relevant bit in the
    > regexp.
    >
    > This isn't mentioned in the Pragmatic Programmers book.
    >
    It is now :)


    Dave Thomas Guest

  5. #5

    Default Re: Natural order sort

    On Monday, September 15, 2003, at 12:07 PM, Alan Davies wrote:
    > Interesting. I always assumed split filtered out the matching
    > sections, but it appears that you can make them appear in the
    > resulting array by putting brackets round the relevant bit in the
    > regexp.
    Yup. That's because it was modeled after the split function in
    Perl, which behaves exactly the same way.

    Given the relative paucity[1] of Ruby doentation, familiarity with
    Perl can be a good way to set your behavioral expectations. Of course,
    if it's something you can test (as opposed to a feature which might or
    might not occur to you at all), that's the best way to determine the
    behavior.

    -Mark

    [1] I did say "relative". There's just a heckuva lot more info out there
    about Perl. The Ruby situation is steadily improving, however, and the
    Pickaxe book is a wondrous thing. :)
    Mark J. Reed Guest

Similar Threads

  1. Updating Sort Order on a field?
    By vkunirs in forum Coldfusion Database Access
    Replies: 2
    Last Post: May 19th, 02:54 PM
  2. PHP Sort order definitions
    By Csaba Gabor in forum PHP Development
    Replies: 0
    Last Post: May 3rd, 11:57 AM
  3. strange sort order
    By Dan Laflamme in forum PERL Beginners
    Replies: 10
    Last Post: January 15th, 05:12 PM
  4. no sort order for clients?
    By Lorenz in forum FileMaker
    Replies: 1
    Last Post: July 28th, 02:08 PM
  5. Sort order
    By hobbit in forum IBM DB2
    Replies: 4
    Last Post: July 11th, 12:58 AM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139