0

I have a SortedDictionary whose value is a List of objects. I want to sort the value(the list) of each key by a given property of the object. In the current situation, I need to sort the list first by objects's lastname, then by firstname. I tried LINQ and it got nasty pretty fast without producing the result.

EDIT:

I have the following structure:

 public class Person { private string firstName; private string lastName; ... } 

I need the dictionary sorted by the key. However, I need every List to be sorted first by Person's lastName, then by firstName.

var dict = new SortedDictionary<string, List<Person>>(); 

I didn't provide code for the sorting because i can't get it to work. That's why I seek help.

6
  • Example code? As a hint: EqualityComparer or something should do the job Commented Jun 17, 2015 at 10:57
  • Please show us some code and the code that didn't produce the results you are after. Then we can give you some constructive feedback and help you understand. Commented Jun 17, 2015 at 10:57
  • 1
    A SortedDictionary is sorted on the key not on the values. Why don't you sort the lists before you add them to the dictionary? Commented Jun 17, 2015 at 10:57
  • @TimSchmelter I know that dictionary is sorted by key. I mainly need it sorted by key. However, I need the values in the lists sorted as well. I cant sort the lists before adding them, because everything is happening dynamic and the input is read from a file. Commented Jun 17, 2015 at 11:05
  • 1
    @zhulien: can the list contain duplicates? If not you can use a SortedSet<Person>. Commented Jun 17, 2015 at 11:21

3 Answers 3

2

You can use List.Sort, LINQ doesn't work in this case because you can't modify the dictionary(f.e. Add or using the Value property) during enumeration:

foreach(var kv in yourSortedDictionary) { kv.Value.Sort((p1, p2) => { int diff = p1.LastName.CompareTo(p2.LastName); if(diff != 0) return diff; return p1.FirstName.CompareTo(p2.FirstName); }); } 

This works even if it would better to add an already sorted list in the first place.

But as i've already mentioned in my comment, if the list cannot contain duplicates you could use a SortedSet<Person> instead of a List<Person>. .NET still lacks of a single value collection type that allows duplicates but is sorted.

Sign up to request clarification or add additional context in comments.

5 Comments

The collection can't be modified in a foreach block, can it?
@zhulien: you're right, i was also afraid that it isn't allowed so i tested it. But only until i changed the Value. Actually the exception is raised on the next iteration.
However, "Unhandled Exception: System.InvalidOperationException: Collection was modified after the enumerator was instantiated.". I used the provided code and also tried that method before posting the question. In the other hand, the solution with the SortedSet i did not come up with before and it may seem to get the job done. Thank you!
@zhulien: yes, i've noticed it myself. Have a look at the modified version. This is more efficient anyway since it doesn't need to create a new list.
Yeah, the Sort method should be the solution. I was just curious is it possible to do it relatively simple using LINQ but this proves to not be the case. However, I should give the SortedSet suggestion a go.Thank you for the input! : )
1

Generally I would create a new IEnumerable instead of trying to alter the existing collection. (This is the Linq way to do it):

IEnumerable<Tuple<string, List<Person>> dict = dict .Select(x => Tuple.Create( x => x.Key, x => x.Value.OrderBy(x => x.LastName).ThenBy(x => x.FirstName))); 

You can put it into a dictionary as well, but it is probably not needed. Either you want to have it sorted (where List is enought) or access by key (where you don't need it to be sorted, use ToDictionary in this case).

You probably don't even need a sorted dictionary as source, when you sort it at the end anyway (and add another OrderBy to the query).

3 Comments

He needs a SortedDictionary because it must be sorted by the key, but the list in the Value must also be sorted.
I need both the access by key and the sort order maintained. I am not a big fan of using Tuples, however. The structure itself just seems somewhat horribly wrong. Thank you for the input, however!
@stefan: yes, but how does OP get the SortedDictionary from the IEnumerable<Tuple<string, List<Person>>? Btw, the x => are redundant in Tuple.Create.
0

I had a similar challenge and solved it by sorting the dictionary containing an object as Value on the fly in the foreach(..) statement.

Here is a sample of how I did it../ given the original scenario...

public class Person { private string firstName; private string lastName; ... } ... Dictionary<string, Person> dictPersons = new Dictionary<string, Person>(); // statements to populate the dictionary with keys and a Person objects. .... foreach(var personEntry in dictPersons.ORderBy(p => p.Value.lastName).ThenBy(p => p.Value.firstName) { ... // When you use the firtName or lastName properties,just refer to it as: Console.WriteLine("LastName: {0} FirstName: {1}", personEntry.Value.lastName, personEntry.Value.firstName); ... } 

Hope this helps some-one who needs it in future...

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.