1

I've got the following Dictionary:

Dictionary<int, int> myDict = new Dictionary<int, int>();
myDict.Add(0, 6);
myDict.Add(1, 10);
myDict.Add(2, 6);
myDict.Add(3, 14);
myDict.Add(4, 10);
myDict.Add(5, 10);

I already know how to get all the duplicates values:

var duplicatedValues = myDict.GroupBy(x => x.Value).Where(x => x.Count() > 1);

But what I want instead is the following: A list with all the keys of the duplicated values, but excluding the last duplicated ones. So in my list above the duplicates values are 10 and 6, and what I want is a list of the following keys: 0, 1, 4 (so excluding 2 and 5).

What is the best way to do this?

Any help would be appreciated. Thanks in advance.

EDIT: I did manage to do it with this piece of code by modifying something I found on the internet, but to be honest I find it a bit dumb to first create a string from the keys and then back into ints. I'm kinda new to the Aggregate-command, so any help how to modify the following code would be welcome:

var lookup = allIDs.ToLookup(x => x.Value, x => x.Key).Where(x => x.Count() > 1);

foreach (var item in lookup) {
    var keys = item.Aggregate("", (s, v) => s + "," + v);
    string[] split = keys.Split(',');
    for (int i = 0; i < split.Length - 1; i++) {
        if (!split[i].Equals("")) {
            Console.WriteLine("removing card nr: " + split[i]);
            CurrentField.removeCardFromField(Convert.ToInt32(split[i]));
        }
    }
}
Kevin Cruijssen
  • 9,153
  • 9
  • 61
  • 135

2 Answers2

3

This should do it:

var firstKeysOfDupeValues = myDict
    .GroupBy(x => x.Value)
    .SelectMany(x => x.Reverse().Skip(1))
    .Select(p => p.Key);
    .ToList();

After grouping by value, the last key for each value group is rejected using .Reverse().Skip(1) (this construct serves double duty: it also rejects the single keys of non-duplicated values) and the keys of the remaining key/value pairs are extracted into the result.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • I like it! I always forget about `Reverse`. The ; on `Select` needs to be removed. – Oliver Mar 11 '14 at 11:13
  • 1
    Barring the unnecessary `ToList()` this is probably about as good as one can get at this, but it's worth noting that the behaviour where dictionaries return contents in order of addition is not specified and could change. Adding a `OrderBy()` can help if it is indeed key ordering rather than addition order one cares about. – Jon Hanna Mar 11 '14 at 11:16
  • @JonHanna: Arguably your comment is more valuable than my answer. Sometimes we lose the forest for the trees. – Jon Mar 11 '14 at 11:18
1

You could use

var allButLastDupKeys = myDict.GroupBy(kv => kv.Value)
    .Where(g => g.Count() > 1)
    .SelectMany(g => g.Take(g.Count() - 1).Select(kv => kv.Key));
string dupKeys = string.Join(",", allButLastDupKeys); // 0,1,4
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939