使用linq获取基于属性的重复项

时间:2017-11-15 18:33:03

标签: c# linq linq-to-entities

我有一堂课说

public class Sample 
{
    public string property;
    public List<string> someListProperty;
    public string someOtherPropery;
}

现在我有一个List<Sample>的对象,我需要迭代这个集合,找出propertysomeListProperty字段具有相同值的项目。

我试过了:

var listSample = List<Sample>()
var result = listSample.GroupBy(x => new { x.property, x.someListProperty})
                       .Where(x => x.Count() > 1).ToList();

但这似乎不起作用,任何指针都会受到高度赞赏。

2 个答案:

答案 0 :(得分:2)

以下评论后更新:正如您所描述的那样,您希望按someOtherProperty而不是someListProperty分组,然后按其分组:

listSample.GroupBy(x => new { x.property, x.someOtherProperty});
  1. 选项1 - 您应该使用SequenceEqual检查两个给定样本的嵌套列表是否相同。为此,请传递自定义IEqualityComparer

    public class SampleComparer : IEqualityComparer<Sample>
    {
        public bool Equals(Sample x, Sample y)
        {
            return x.property == y.property &&
                Enumerable.SequenceEqual(x.someListProperty, y.someListProperty);
        }
        public int GetHashCode(Sample obj)
        {
            // Implement
        }
    }
    

    (用于实施GetHashCode请参阅:What is the best algorithm for an overridden System.Object.GetHashCode?

    然后:

    var result = list.GroupBy(k => k, new SampleComparer());
    

    测试了以下数据并返回3组:

    List<Sample> a = new List<Sample>()
    {
        new Sample { property = "a", someListProperty = new List<string> {"a"}, someOtherPropery = "1"},
        new Sample { property = "a", someListProperty = new List<string> {"a"}, someOtherPropery = "2"},
        new Sample { property = "a", someListProperty = new List<string> {"b"}, someOtherPropery = "3"},
        new Sample { property = "b", someListProperty = new List<string> {"a"}, someOtherPropery = "4"},
    };
    
  2. 选项2 - 不是创建实现界面的类,而是使用ProjectionEqualityComparer,如下所述:Can you create a simple 'EqualityComparer<T>' using a lambda expression

  3. 作为旁注,而不是在使用中使用Count

    var result = list.GroupBy(k => k, new SampleComparer())
                     .Where(g => g.Skip(1).Any());
    

    正如你想要的只是检查组中有多个项目而不是实际数量,这只会通过两个项目,而不是在O(n)操作中计算所有项目。

答案 1 :(得分:0)

像这样调整你的linq:

    static void Main(string[] args)
    {
        var samples = new List<Sample>
        {
            new Sample("p1", "aaa,bbb,ccc,ddd"),
            new Sample("p1", "bbb,ccc,xxx"),
            new Sample("p2", "aaa,bbb,ccc"),
            new Sample("p1", "xxx")
        };

        var grp = samples.GroupBy(b => b.property)
            .Where(a => a.Key == "p1")
            .SelectMany(s => s.ToList())
            .Where(b => b.someListProperty.Contains("ccc"));

        foreach (var g in grp)
            System.Console.WriteLine(g.ToString());

        System.Console.ReadLine();
    }

    private class Sample
    {
        public string property;

        public List<string> someListProperty;

        public string someOtherPropery;

        public Sample(string p, string props)
        {
            property = p;
            someListProperty = props.Split(',').ToList();
            someOtherPropery = string.Concat(from s in someListProperty select s[0]);
        }

        public override string ToString()
        {
            return $"{property} - {string.Join(", ", someListProperty)} -"
                       + $" ({someOtherPropery})";
        }
    }

误读 - 我读过你想要那些&#34;一些&#34; someListProperty的{​​{1}}应该是您要从分组中过滤的那些。

你可以像这样分组以实现它:

var grp = samples
    // choose a joiner thats not in your somePropertyList-data
    .GroupBy(b => $"{b.property}:{string.Join("|", b.someListProperty)}")
    .Where(g => g.Skip(1).Any())
    .SelectMany(s => s.ToList())

但请注意,这有点hackish,取决于您的数据。你基本上将所有有趣的东西分组,然后选择所有有多种结果的东西。