samuelwcm
samuelwcm

Reputation: 96

C# - sorting by a property

I am trying to sort a collection of objects in C# by a custom property. (For context, I am working with the Twitter API using the Twitterizer library, sorting Direct Messages into conversation view)

Say a custom class has a property named label, where label is a string that is assigned when the class constructor.

I have a Collection (or a List, it doesn't matter) of said classes, and I want to sort them all into separate Lists (or Collections) based on the value of label, and group them together.

At the moment I've been doing this by using a foreach loop and checking the values that way - a horrible waste of CPU time and awful programming, I know. I'm ashamed of it.

Basically I know that all of the data I have is there given to me, and I also know that it should be really easy to sort. It's easy enough for a human to do it with bits of paper, but I just don't know how to do it in C#.

Does anyone have the solution to this? If you need more information and/or context just ask.

Upvotes: 1

Views: 1411

Answers (3)

atevans
atevans

Reputation: 373

It sounds to me like mlorbetske was correct in his interpretation of your question. It sounds like you want to do grouping rather than sorting. I just went at the answer a bit differently

var originalList = new[] { new { Name = "Andy", Label = "Junk" }, new { Name = "Frank", Label = "Junk" }, new { Name = "Lisa", Label = "Trash" } }.ToList();

var myLists = new Dictionary<string, List<Object>>();

originalList.ForEach(x =>
    {
        if (!myLists.ContainsKey(x.Label))                
            myLists.Add(x.Label,new List<object>());
        myLists[x.Label].Add(x);

    });

Upvotes: 0

mlorbetske
mlorbetske

Reputation: 5649

You say sorting but it sounds like you're trying to divide up a list of things based on a common value. For that you want GroupBy.

You'll also want ToDictionary to switch from an IGrouping as you'll presumably be wanting key based lookup.

I assume that the elements within each of the output sets will need to be sorted, so check out OrderBy. Since you'll undoubtedly be accessing each list multiple times you'll want to collapse it to a list or an array (you mentioned list) so I used ToList

//Make some test data
var labels = new[] {"A", "B", "C", "D"};
var rawMessages = new List<Message>();

for (var i = 0; i < 15; ++i)
{
    rawMessages.Add(new Message
    {
        Label = labels[i % labels.Length],
        Text = "Hi" + i,
        Timestamp = DateTime.Now.AddMinutes(i * Math.Pow(-1, i))
    });
}

//Group the data up by label
var groupedMessages = rawMessages.GroupBy(message => message.Label);

//Convert to a dictionary for by-label lookup (this gives us a Dictionary<string, List<Message>>)
var messageLookup = groupedMessages.ToDictionary(
            //Make the dictionary key the label of the conversation (set of messages)
            grouping => grouping.Key, 
            //Sort the messages in each conversation by their timestamps and convert to a list
            messages => messages.OrderBy(message => message.Timestamp).ToList());

//Use the data...
var messagesInConversationA = messageLookup["A"];
var messagesInConversationB = messageLookup["B"];
var messagesInConversationC = messageLookup["C"];
var messagesInConversationD = messageLookup["D"];

Upvotes: 1

Dave Zych
Dave Zych

Reputation: 21887

Have you tried Linq's OrderBy?

var mySortedList = myCollection.OrderBy(x => x.PropertyName).ToList();

This is still going to loop through the values to sort - there's no way around that. This will at least clean up your code.

Upvotes: 3

Related Questions