views:

70

answers:

2

hello all , i have the following problem I have a list with strings for example (100_1, 100_2 .... , 100_10)

I sort the list with following code

extraImgsRaw.Sort((photo1, photo2) => photo1.CompareTo(photo2));

the result of this is : 100_1, 100_10, 100_2, 100_3 and so on

the result that I want is a logical compare like 100_1, 100_2 and then 100_10 so I prefer a Natural numeric sort not a Alphabetic sort. Do I need to write my own compare class that implements the ICompare interface or there is a build method in LINQ that does that?

thank you in advance

+1  A: 

Split and compare elements,

Here is one I wrote for 'versions'.

  /// <summary>
  /// Only works for version numbers in the form a ( . b ( . c ( . d )? )? )?
  /// </summary>
  public class VersionComponents : IComparable<VersionComponents>
  {
    readonly int[] components;

    int[] GetComponents(string cpnumber)
    {
      var tokens = cpnumber.Split(".".ToCharArray(), 
                                   StringSplitOptions.RemoveEmptyEntries);
      return tokens.Select(x => Convert.ToInt32(x)).ToArray();
    }

    public VersionComponents(string cpnumber)
    {
      components = GetComponents(cpnumber);
    }

    public int this[int index]
    {
      get { return components.Length > index ? components[index] : 0; }
    }

    public int CompareTo(VersionComponents other)
    {
      for (int i = 0; i < components.Length || 
                      i < other.components.Length; i++)
      {
        var diff = this[i].CompareTo(other[i]);
        if (diff != 0)
        {
          return diff;
        }
      }

      return 0;
    }
  }
leppie
+4  A: 

There's nothing built-in, but if the data is exactly as shown in your question then it shouldn't be too difficult to knock up a Comparison<T> to do this for you:

extraImgsRaw.Sort((x, y) =>
                  {
                      // error checking etc removed for brevity
                      int[] xi = x.Split('_').Select(int.Parse).ToArray();
                      int[] yi = y.Split('_').Select(int.Parse).ToArray();

                      int c = xi[0].CompareTo(yi[0]);
                      return (c != 0) ? c : xi[1].CompareTo(yi[1]);
                  });
LukeH
+1 I was writing the same answer :)
digEmAll
A class or type would be better in this case IMO. You are likely to re-use it.
leppie
@leppie: If it's going to be re-used then I agree that an `IComparer<T>` with more error handling etc is the way to go. If it's just a quick one-off job where the user knows the exact format of the data then the `Comparison<T>` will usually suffice.
LukeH
+1 for `.Select(int.Parse)` versus `.Select(i => int.Parse(i))`
Marc