部分区别Linq

时间:2015-02-19 22:15:42

标签: c# linq

我有一个对象列表。这些物体具有例如“值”。

       var lst = new List<TestNode>();

       var c1 = new TestNode()
        {
          Value = "A",
        };

        lst.Add(c1);

        var c2 = new TestNode()
        {
            Value = "A",
        };

        lst.Add(c2);

        var c3 = new TestNode()
        {
            Value = "B",
         };

        lst.Add(c3);

        var c4 = new TestNode()
        {
             Value = "B",
        };

        lst.Add(c4);

我想说的是:

lst.PartialDistinct(x => x.Value == "A")

这应仅与谓词不同,并且在打印生成的IEnumerable的“值”时,结果应为:

A
B
B

我已经找到了DistinctBy的解决方案,可以定义一个Key-Selector。但结果当然是:

A
B

Cyral的第一个答案完成了这项工作。所以我接受了它。但Scott的回答实际上是一个PartialDistinct()方法,看起来它解决了我所有的问题。

好吧,以为它是用斯科特的解决方案解决的,但事实并非如此。也许我在进行单元测试时犯了错误......或者我不知道。问题是:

if(seen.Add(item)) 

这不会过滤掉值为“A”的其他对象。我认为这是因为它在放入hashset时依赖于引用相等性。

我最终得到了以下解决方案:

public static IEnumerable<T> PartialDistinct<T>(this IEnumerable<T> source Func<T, bool> predicate)
    {
        return source
            .Where(predicate)
            .Take(1)
            .Concat(source.Where(x => !predicate(x)));
    }

4 个答案:

答案 0 :(得分:4)

您可以按Value进行分组,并使用SelectMany执行'条件展平',即只从“A”组中获取一个元素,并从其余部分中获取所有元素基团:

var result = lst.GroupBy(x => x.Value)
                .SelectMany(g => g.Key == "A" ? g.Take(1) : g);

答案 1 :(得分:3)

尝试找到与您的值匹配的元素,获取其中的第一个元素,然后将其与所有与您的值不匹配的元素加入。

var match = "A";
var result = lst
    .Where(x => x.Value == match)
    .Take(1)
    .Concat(lst
    .Where(x => x.Value != match))
    .Select(x => x.Value);

答案 2 :(得分:3)

如果您希望在TestNodeValue == A加上Value != A加上正常结果集,public static class ExtensionMethods { public static IEnumerable<T> PartialDistinct<T>(this IEnumerable<T> source, Func<T, bool> filter) { return PartialDistinct(source, filter, EqualityComparer<T>.Default); } public static IEnumerable<T> PartialDistinct<T>(this IEnumerable<T> source, Func<T, bool> filter, IEqualityComparer<T> comparer) { HashSet<T> seen = new HashSet<T>(comparer); foreach (var item in source) { if (filter(item)) { if (seen.Add(item)) { yield return item; } } else { yield return item; } } } 只执行该过程,并将其包含在扩展方法中。

{{1}}

答案 3 :(得分:0)

创建两个不同的列表并连接它们也是一种方式。

var answer = lst.Where(val=>val == "A").Select(note=>note.Value).Distinct().Concat(
        lst.Where(node => node.Value == "B").Select(node => node.Value));