Reputation: 785
I am trying to sort an ObservableCollection that has items that must be sorted partially by name on some and preserve the sort as the data is already given from it source.
The data comes to me as:
The result of the above will print as below:
First Item
A Second Item
Third Item
Item 1
Item 10
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Here is the collection sample to generate the above data (This is just a sample I created to give me data like above):
ObservableCollection<MyObject> items = new ObservableCollection<MyObject>();
items.Add(new MyObject { ItemID = 1, Name = "First Item", Category = "0" });
items.Add(new MyObject { ItemID = 2, Name = "A Second Item", Category = "0" });
items.Add(new MyObject { ItemID = 3, Name = "Third Item", Category = "0" });
items.Add(new MyObject { ItemID = 4, Name = "Item 1", Category = "1" });
items.Add(new MyObject { ItemID = 13, Name = "Item 10", Category = "1" });
items.Add(new MyObject { ItemID = 5, Name = "Item 2", Category = "1" });
items.Add(new MyObject { ItemID = 6, Name = "Item 3", Category = "1" });
items.Add(new MyObject { ItemID = 7, Name = "Item 4", Category = "1" });
items.Add(new MyObject { ItemID = 8, Name = "Item 5", Category = "1" });
items.Add(new MyObject { ItemID = 9, Name = "Item 6", Category = "1" });
items.Add(new MyObject { ItemID = 10, Name = "Item 7", Category = "1" });
items.Add(new MyObject { ItemID = 11, Name = "Item 8", Category = "1" });
items.Add(new MyObject { ItemID = 12, Name = "Item 9", Category = "1" });
foreach (var item in items)
{
Console.WriteLine(item.Name);
}
Here is my MyObject
public class MyObject
{
public int ItemID { get; set; }
public string Category { get; set; }
public string Name { get; set; }
}
I want the above to be sorted as:
First Item // This must be preserved like this
A Second Item // This must be preserved like this
Third Item // This must be preserved like this
Item 1 // Rest below must be sorted like below and not Item 1, Item 11...
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
If I use, var sorted = items.OrderBy(x => x.Name)
I don't get the result what I want.
How can I get the sorting be done only on partial items?
Based on the comment. I cant rely on the ItemID. It is not reliable. The only piece I can rely to sort in the name and category.
This is my final solution I did:
Func<string, object> convert = str =>
{
int k;
if (int.TryParse(str, out k))
return k;
return str;
};
var sorted = items.Where(x => x.Category != "1").Union(items.Where(x => x.Category == "1")
.OrderBy(str => Regex.Split(str.Name.Replace(" ", ""), "([0-9]+)").Select(convert),
new EnumerableComparer<object>()));
foreach (var item in sorted)
{
Console.WriteLine(item.Name);
}
I used Tim. S's link for implementing the natural sort comparer with Badak's idea.
Upvotes: 1
Views: 260
Reputation: 646
Or you can distinguish items by
foreach (var item in items.Where(X => !X.Name.StartsWith("Item")).Union(items.Where(X => X.Name.StartsWith("Item")).OrderBy(X => Convert.ToInt32(X.Name.Replace("Item ", "")))))
{
Console.WriteLine(item.Name);
}
This works if and only if the the items that starts with Item are followed by an int, other elements stays above
Upvotes: 1