我正在尝试按其两个属性过滤对象列表。如果存在重复,则可以删除对象。如果第一个属性与第二个属性具有相同的值,并且第二个属性具有与第一个属性相同的值。
示例:
object0: id0=1A, id1=2B
object1: id0=1A, id1=2B
object2: id0=1A, id1=3C
object3: id0=2B, id1=1A
object4: id0=2B, id1=3C
object5: id0=3C, id1=2B
所以发生以下情况: object0删除object1和object 3 object4删除object5
最终输出:
object0: id0=1A, id1=2B
object2: id0=1A, id1=3C
object4: id0=2B, id1=3C
现在我有FOR循环这样做,但我很想知道是否有办法用linq做到这一点?我尝试过使用Distinct,DistinctBy和GroupBy。我是否需要自己进行比较以完成此操作?
答案 0 :(得分:4)
这样做。
source
.GroupBy(x => new {min = Math.Min(x.Id0, x.Id1), max = Math.Max(x.Id0, x.Id1)})
.Select(g => g.First());
测试。
public void SillyTuplesTest()
{
List<Tuple<string, int, int>> source = new List<Tuple<string, int, int>>()
{
Tuple.Create("object0", 1, 2),
Tuple.Create("object1",1, 2),
Tuple.Create("object2",1, 3),
Tuple.Create("object3",2, 1),
Tuple.Create("object4",2, 3),
Tuple.Create("object5",3, 2)
};
var result = source
.GroupBy(x => new { min = Math.Min(x.Item2, x.Item3), max = Math.Max(x.Item2, x.Item3) })
.Select(g => g.First());
foreach (Tuple<string, int, int> resultItem in result)
{
Console.WriteLine("{0} ({1}, {2})", resultItem.Item1, resultItem.Item2, resultItem.Item3);
}
}
结果
object0 (1, 2)
object2 (1, 3)
object4 (2, 3)
对于字符串,您可以使用:
source
.GroupBy(x =>
string.Compare(x.Id0, x.Id1, false) < 0 ?
new {min = x.Id0, max = x.Id1} :
new {min = x.Id1, max = x.Id0})
.Select(g => g.First());
如果你有一个未知数量的字符串,你可以使用HashSet<string>
作为密钥和SetComparer。
IEqualityComparer<HashSet<string>> comparer =
HashSet<string>.CreateSetComparer();
source
.GroupBy(x => new HashSet<string>(x.GetStrings()), comparer)
.Select(g => g.First());
答案 1 :(得分:-1)
创建一个扩展方法,例如:
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
var seenKeys = new HashSet<TKey>();
return source.Where(element => seenKeys.Add(keySelector(element)));
}
然后使用它。
了解这对您有何帮助。