0

I have such class:

public class Item
{
    public int Id {get;set;}
    public string A {get;set;}
    public string B {get;set;}
    public string C {get;set;}
}

And now I have an example dictionary which looks like this:

var dict = new Dictionary<<int, List<Item>>()
{
    { 
       1, 
       new List<Item>() 
       { 
          new Item { Id = 1, A = "aaa", B = "bbb", C = "ccc" }, 
          new Item { Id = 2, A = "q", B = "w", C = "e" }
       } 
    },
    { 
       2, 
       new List<Item>() 
       { 
          new Item { Id = 3, A = "aaa", B = "bbb", C = "ccc" }, 
          new Item { Id = 4, A = "qqq", B = "www", C = "eee" }
       } 
    },
    { 
       3, 
       new List<Item>() 
       { 
          new Item { Id = 1, A = "aaa", B = "bbb", C = "ccc" }, 
          new Item { Id = 5, A = "some", B = "other", C = "case" }
       } 
    },
};

What I need to do is to find all Item's which have equal values on properties A, B, C for ALL keys, so as an output there should be an IEnumerable<Item> / List<Item>.

For the example above, the output would contain a single Item element with values:

A = "aaa", B = "bbb", C = "ccc"

because for each dictionary key an Item object with those exact values exist. Id for this object could be taken from first Item that matches, so it could be equal to 1

How would a LINQ query look for this?

10
  • How do you define "similar"? Commented Jul 25, 2018 at 8:18
  • 3
    "How would a LINQ query look for this?" How does your solution look like? We´re not here to do your task, you have to think yourself. We may help you if you have a sopecific problem somewhere. Commented Jul 25, 2018 at 8:19
  • 2
    Perhaps an icomparer on Item then loop on all value, from this point it should be easy to know if one item is dupe or not . Commented Jul 25, 2018 at 8:24
  • 1
    You should start with a simple for loop and later on try to convert it to LINQ. Commented Jul 25, 2018 at 8:25
  • 4
    So why you not trying to do that? I can't see any failing points in your question. It looks like a task, not a question of specific problem. Commented Jul 25, 2018 at 8:28

3 Answers 3

2

The query you're looking for looks something like this:

dict .SelectMany(d => d.Value) .Where(d => dict.All(di => di.Value.Any(v => v.A == d.A && v.B == d.B && v.C == d.C))) .GroupBy(d => new { A = d.A, B = d.B, C = d.C }) .Select(d => d.Key) .ToList();

Quick explanation:

  1. Make a list of all items
  2. Iterate through all items, only keep dictionary items which all have the item (based on property A, B & C)
  3. Group the items on property A, B, C (because id is different for the items)
  4. Select the key (anonymous class with property A, B, C)
Sign up to request clarification or add additional context in comments.

Comments

1

Alternative solution would be to use Aggregate, and override GetHash in your Item class, like this:

dict.SelectMany(x => x.Value)
    .Aggregate(new Dictionary<Item, int>(), (map, item1) => 
        {
            if (map.ContainsKey(item1))
                map[item1]++;
            else map[item1] = 0;
            return map;
        })
   .Where(y => y.Value > 0)
   .Select(pair =>pair.Key);

And Item Override:

    public bool Equals(Item other)
    {
        return A == other?.A && B == other.B && C == other.C;
    }

    public override int GetHashCode()
    {
        int hash = 13;
        hash = (hash * 7) + A.GetHashCode();
        hash = (hash * 7) + B.GetHashCode();
        hash = (hash * 7) + C.GetHashCode();

        return hash;
    }

Comments

1

With a IEqualityComparer, you can simply: Select all Value, Group, Filter the unique, Select your item.

var flatAllValues = dict.SelectMany(x => x.Value).ToList();
var group = flatAllValues
     .GroupBy(p => p, new ItemComparer())
     .Where(g => g.Count() > 1)
     .Select(g =>  g.Key);

IEqualityComparer implementation:

class ItemComparer : IEqualityComparer<Item>
{
    public bool Equals(Item i1, Item i2)
    {
        if (i1 == null && i2 == null)
            return true;
        else if (i2 == null | i1 == null)
            return false;
        else if (i2.A == i1.A
            && i2.B == i1.B
            && i2.C == i1.C)
            return true;
        else
            return false;
    }

    public int GetHashCode(Item i)
    {
        unchecked
        {
            int hash = 17;
            hash = hash * 23 + i.A.GetHashCode();
            hash = hash * 23 + i.B.GetHashCode();
            hash = hash * 23 + i.C.GetHashCode();
            return hash;
        }
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.