0

I have a class with one property "Name" containing names like "1_[AnnualRevenue]","2_[ResellerType]","3_xxx"....

my class is like

class xxx
{
 private string fileName;
 public string FileName
        {
            get { return fileName; }
            set { fileName = value; }
        }
}

And I am assigning the values to the object of the class. like xxx.FileName="1_[AnnualRevenue]";

Now I have a list class. And now sort the list according to this class property.

Now I want to sort the field according to the numeric order, I mean 1 first 2 second and so on.

And then write it to filestream.

Could any body help me with this. Thanks in advance.

5
  • 2
    Do you mean you have a list of classes that you want to sort by their Name property? It would be helpful if you showed a code sample of the class and how you're storing the instances of it. Commented Jan 14, 2015 at 6:27
  • show your class please and a example of the values Commented Jan 14, 2015 at 6:28
  • Are you talking about the 'N_' numbers at the start of your file name? Commented Jan 14, 2015 at 6:36
  • dotnetperls.com/alphanumeric-sorting this can get you started Commented Jan 14, 2015 at 6:37
  • If you are considering _ then you are not doing numerical sorting that's Alpha numeric sorting, which would put 10_a ahead of 2_a Commented Jan 14, 2015 at 6:46

3 Answers 3

2

Since the property is a String but you want to sort it numerically, probably the best way would be to implement IComparable on your class and then put your custom sort code in the CompareTo method. Then you don't have to write a more complex Lambda statement each time you want to Sort a list, you can just call the Sort() method on the list.

You can also handle cases where the FileName property does not contain an underscore or is null, rather than getting exceptions in your OrderBy code (which is what would happen with most of the other answers).

I made a couple of other changes also - override the ToString method so you can easily display the value to the console window, and used Automatic property syntax for the FileName property so we can remove the backing field:

class xxx : IComparable<xxx>
{
    public string FileName { get; set; }

    public int CompareTo(xxx other)
    {
        // Short circuit if any object is null, if the
        // Filenames equal each other, or they're empty
        if (other == null) return 1;
        if (FileName == null) return (other.FileName == null) ? 0 : -1;
        if (other.FileName == null) return 1;
        if (FileName.Equals(other.FileName)) return 0;
        if (string.IsNullOrWhiteSpace(FileName)) 
            return (string.IsNullOrWhiteSpace(other.FileName)) ? 0 : -1; 
        if (string.IsNullOrWhiteSpace(other.FileName)) return 1;

        // Next, try to get the numeric portion of the string to compare
        int thisIndex;
        int otherIndex;

        var thisSuccess = int.TryParse(FileName.Split('_')[0], out thisIndex);
        var otherSuccess = int.TryParse(other.FileName.Split('_')[0], out otherIndex);

        // If we couldn't get the numeric portion of the string, use int.MaxValue
        if (!thisSuccess)
        {
            // If neither has a numeric portion, just use default string comparison
            if (!otherSuccess) return FileName.CompareTo(other.FileName);
            thisIndex = int.MaxValue;
        }
        if (!otherSuccess) otherIndex = int.MaxValue;

        // Return the comparison of the numeric portion of the two filenames
        return thisIndex.CompareTo(otherIndex);
    }

    public override string ToString()
    {
        return FileName;
    }
}

Now, you can just call Sort on your list:

List<xxx> list = new List<xxx>
{
    new xxx {FileName = "13_a"},
    new xxx {FileName = "8_a"},
    new xxx {FileName = null},
    new xxx {FileName = "1_a"},
    new xxx {FileName = "zinvalid"},
    new xxx {FileName = "2_a"},
    new xxx {FileName = ""},
    new xxx {FileName = "invalid"}
};

list.Sort();

Console.WriteLine(string.Join("\n", list));

// Output (note the first two are the empty string and the null value):
// 
// 
// 1_a
// 2_a
// 8_a
// 13_a
// invalid
// zinvalid
Sign up to request clarification or add additional context in comments.

1 Comment

By the way, not sure how you're coming up with the FileNames, but if you're adding the number to them in code somewhere, it would probably be easier to just give your class an int Rank {get;set;} property and set that in addition to the FileName. If you did this, then you could just do: list.OrderBy(i => i.Rank) and you wouldn't have to create a custom CompareTo method.
2

You can use LINQ to do that for you

List<xxx> orderedList = unOrderedList.OrderBy(o => Convert.ToInt32(o.FileName.Split('_').First())).ToList();

Editted the answer on behalf of the comments - pointing out that indeed we need to convert to integers to order correctly.

2 Comments

Where would it put 10_a, 20_a, solution is same as above
Though I need to try, but this sounds good, pure numerical ordering
2

You can do like following to sort the list:

List<xxx> list = new List<xxx> 
{ 
    new xxx { FileName = "3_a" }, 
    new xxx { FileName = "1_a" }, 
    new xxx { FileName = "2_a" }, 
    new xxx { FileName = "8_a" } 
};
var sorted = list.OrderBy(it => Convert.ToInt32(it.FileName.Split('_')[0]));//using System.Linq;

And you can write the list to disk file as below:

using (TextWriter tw = new StreamWriter("C:\\FileNames.txt"))
            {
                foreach (var item in sorted)
                {
                    tw.WriteLine(item.FileName.ToString());
                }
            }

2 Comments

Where would it put 10_a, 20_a
Nice! Probably don't need to call .ToString() on FileName... :p

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.