Selecting Items with the same subcollection using LINQ
Here is the pseudo case:
class parent{
string name; //Some Property
List<int> myValues;
.......
}
........
//Initialize some parent classes
List<parent> parentList = new List<parent>();
parentList.add(parent123); //parent123.myValues == {1,2,3}
parentList.add(parent456); //parent456.myValues == {4,5,6}
parentList.add(parentMatch); //parentMatch.myValues == {1,2,3}
What I am aiming for is a query which retrieves a List of parent objects where their myValues Lists are equiva开发者_开发问答lent. In this case it would return parent123 and parentMatch.
So you can wrap the logic up and just use GroupBy
if you implement an IEqualityComparer
:
class IntegerListComparer : IEqualityComparer<List<int>>
{
#region IEqualityComparer<List<int>> Members
public bool Equals(List<int> x, List<int> y)
{
//bool xContainsY = y.All(i => x.Contains(i));
//bool yContainsX = x.All(i => y.Contains(i));
//return xContainsY && yContainsX;
return x.SequenceEqual(y);
}
public int GetHashCode(List<int> obj)
{
return 0;
}
#endregion
}
Call it like so:
var results = list
.GroupBy(p => p.MyValues, new IntegerListComparer())
.Where(g => g.Count() > 1)
.SelectMany(g => g);
Very silly solution:
var groups = list.GroupBy(p => string.Join(",", p.list.Select(i => i.ToString()).ToArray()))
.Where(x => x.Count() > 1).ToList();
Result:
an IEnumerable
of groups containing parent objects having list with same int (in the same order).
If you need to match list of elements in any order (i.e. 1,2,3 == 3,1,2), just change p.list
to p.list.OrderBy(x => x)
.
Plus, if you're targeting framework 4.0, you can avoid ToArray
and ToString
EDIT:
added a where to filter single-occurrence groups.
Now if you have these parents:
parent A 1,2,3
parent B 1,2,3
parent C 1,2,3
parent D 4,5,6
parent E 4,5,6
parent F 7,8,9
it returns:
(A,B,C) - (D,E)
Try this:
var matches = (from p1 in parentList
from p2 in parentList
let c1 = p1.myValues
let c2 = p2.myValues
where p1 != p2 &&
c1.All(child => c2.Contains(child)) &&
c2.All(child => c1.Contains(child))
select p1).Distinct();
精彩评论