1

My question is not duplicate as the one that you have marked is searching List and I am trying to search Dictionary.

I have a Dictionary<string, Player>.

Player is an object with the properties GameID, Index and more. My dictionary key is player's index. I want to check if dictionary contains two Players with same GameID (the index will be different for those). One way of doing this is iterating with foreach over dictionary values and use an variable which would be incremented every time it encounters certain GameID. But I was wondering if there is a way to do this by using linq? If there is, that solution would probably be better.

niksrb
  • 459
  • 7
  • 25
  • 2
    Looping over a list or a dictionary, what's the big difference? – Julian Jun 02 '19 at 10:36
  • Specifically: in this part of code `.Values`. But I got used to people who are prone to hating and giving minuses here on stackoverflow just because they understand something better then the others – niksrb Jun 02 '19 at 10:41
  • Just because you are using different container class does not make your question unique. Even w/o `Values` property, `Dictionary` is `IEnumerable>`. And LINQ to Objects operate on `IEnumerable` regardless of what class is implementing it (array, list, dictionary, whatever). So it really doesn't matter what is the actual collection type. The only important is the *element type*. Take the accepted answer from the duplicate question, replace `lstNames.GroupBy(n => n)` with `dict.GroupBy(x => x.Value.GameID)` and there you go. – Ivan Stoev Jun 02 '19 at 13:20
  • @IvanStoev If there are people ready to help (and there are at least 3 of them here, based on answers) why do you have to point out it's a duplicate? You don't want to help? No problem, nobody forces you to, just move on. – niksrb Jun 02 '19 at 18:34

3 Answers3

2

Dictionaries, differently than Lists, provide a constant complexity to access one of its entries.

The purpose of a Dictionary is to map a Key -> Value relation where keys are unique. By using a generic index as Key, there is no advantage over a List<Player>.

Therefore, rather than answering an inefficiently formulated problem, I will provide a more efficient solution reformulating the original question.

You can find an implementation of a Multimap (dictionary with multiple keys) where you can represent a GameID-> Index relationship and count occurrences, here: multimap in .NET

Compared to the (currently) accepted answer, which has linear time complexity ( O(N) ) and grows worse and worse for larger Dictionaries or Lists, even with the optimizations within IQueryable in Linq, this provides a constant complexity.

Attersson
  • 4,755
  • 1
  • 15
  • 29
2

Use LINQ's GroupBy and then filter groups larger than one:

var result = dict.Values
             .GroupBy(x => x.GameID)
             .Where(x => x.Count() > 1)
             .Select(g => g.First()); // Take one of the duplicates

Example


If you know the GameID to look for you can just use

var gameID = 1
var isDuplicate = dict.Values
                  .Where(x => x.GameID == gameID)
                  .Count() > 1;
adjan
  • 13,371
  • 2
  • 31
  • 48
  • Actually, at the moment of search I know exactly which `GameID` I am looking for, so I guess there should be another `WHERE` with condition `x.GameID == 1` for example? I am not sure how it should be written using `linq`. – niksrb Jun 02 '19 at 10:27
  • @niksrb see my edit – adjan Jun 02 '19 at 10:31
  • Yes, trying it now in my code, will report soon – niksrb Jun 02 '19 at 10:33
  • Why do we need to group ALL the data if we just want to find out whether there are duplicates or not ? Imagine that there are 1 000 000 records and duplicated records are records on position 1 and 10... This solution will group the whole 1M records – Fabjan Jun 02 '19 at 10:41
  • @Fabjan You dont know where the duplicates are... They could be 1 and 999999. As I understood, he wants to know *which* are the duplicates, not whether there are any. – adjan Jun 02 '19 at 10:44
  • @Adrian How does that justify creation of up to 1 000 000 `IGroupping`s that OP doesn't need ? No the OP want's to know whether there *are* duplicates or not. – Fabjan Jun 02 '19 at 10:47
  • @Fabjan Thats why he asked for a solution that explicitly queries a certian GroupID? I guess not. Youre not even reading the comments – adjan Jun 02 '19 at 10:48
0

suppose that we have these records:

    Dictionary<string, Player> myDic = new Dictionary<string, Player>();
    Player p1 = new Player() { GameID = 1, Index = "a" };
    Player p2 = new Player() { GameID = 2, Index = "b" };
    Player p3 = new Player() { GameID = 1, Index = "c" };
    Player p4 = new Player() { GameID = 3, Index = "d" };
    myDic.Add(p1.Index, p1);
    myDic.Add(p2.Index, p2);
    myDic.Add(p3.Index, p3);
    myDic.Add(p4.Index, p4);

You can try this:

 var duplicates = myDic.Values
                .GroupBy(x => x.GameID)
                .SelectMany(p =>
                    p.Select((j, i) => new { j.Index, j.GameID, rn = i + 1 }))
                .Where(x => x.rn > 1).ToList();

            foreach (var dups in duplicates)
            {
                Console.WriteLine($"record with GameId: {dups.GameID} at Index: {dups.Index} is duplicate!");
            }
Vahid Farahmandian
  • 6,081
  • 7
  • 42
  • 62