LINQ在多个属性上双向不同

本文关键字:属性 LINQ | 更新日期: 2023-09-27 18:26:59

我正在尝试通过对象列表的两个属性来过滤它。如果存在重复,则可以删除对象。如果第一个属性与第二个属性具有相同的值,而第二个特性与第一个属性具有同样的值。

示例:

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

因此,会发生以下情况:对象0删除对象1和对象3对象4删除对象5

最终输出:

object0: id0=1A, id1=2B
object2: id0=1A, id1=3C
object4: id0=2B, id1=3C 

现在我有FOR循环来做这个,但我想知道是否有一种方法可以用linq来做这个?我尝试过使用Distinct、DistinctBy和GroupBy。我需要自己进行比较才能完成这项工作吗?

LINQ在多个属性上双向不同

这样做。

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());

创建一个扩展方法,例如:

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)));
}

然后使用它。

看看这对你有什么好处。