如何编写LINQ查询以基于特定属性检索不同的记录?

5
我有一个对象数组,我尝试使用下面展示的LINQ查询检索特定和的记录。我的当前查询使用函数来区分所有5个属性。如何基于、、和属性检索不同的记录? :
[
    {
    "DataTestPlanID": 0,
    "DataID": 19148,
    "TestPlanName": "string",
    "TCIndexList": "string",
    "ProductID": 2033915
  },
    {
    "DataTestPlanID": 0,
    "DataID": 19148,
    "TestPlanName": "string",
    "TCIndexList": "string",
    "ProductID": 2033915
  },
      {
    "DataTestPlanID": 0,
    "DataID": 19149,
    "TestPlanName": "string",
    "TCIndexList": "string",
    "ProductID": -2642
  }

]

LINQ

            DataTestPlans_DataID_ProductID = DataTestPlans.Where(c => c.DataID == DataID_ProductID_Record.DataID && c.ProductID == DataID_ProductID_Record.ProductID).Distinct();

1
你可以编写一个实现 IComparer 接口的类,并将其实例传递给 Distinct() 方法。 - itsme86
1
可能是如何在LINQ中使用多个字段的Distinct()方法的重复问题。 - Klinger
Klinger - 你所指的内容没有被接受的答案。 - user3508811
5个回答

4
你可以像这样做...
DataTestPlans.Where(c => c.DataID == YourInput && c.ProductID == YourInput)
             .GroupBy(x => new {x.DataID,x.TestPlanName,x.TCIndexList,x.ProductID})
             .Select(x => x.First());

1
是的,基本上就是这样。请注意,在此示例中,未分组字段的值基本上是随机的。如果您关心该值,则必须找到某种方式从组中聚合它。另外,FirstOrDefault()不应该是必需的,因为每个组都至少有一个成员,否则它就不是一个组。 (因此,可以只使用First()。) - Chris Berger
我喜欢你的解决方案,但考虑用.SelectMany(x => x.Take(1))替换.Select(x => x.FirstOrDefault());。这是一种更清晰的方法,可以防止在GroupBy之后进行过滤时出现错误的默认值。 - Enigmativity
@ChrisBerger - 在使用.GroupBy(...)之后使用.First()时,如果您重构并在它们之间放置一个.Select(x => x.Where(...))会产生错误的值。 - Enigmativity
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Sateesh Pagolu
@user3508811:不需要使用SelectMany。请检查更新后的答案。 - Sateesh Pagolu
显示剩余6条评论

1

有两种方法可以实现,都在这个问题中有详细介绍,不需要使用IComparer。下面是一个快速示例,您可以尝试一下(我没有使用您的实际对象,因为这样更容易解释):

class Program
{
    static void Main(string[] args)
    {
        var persons = Setup();

        //option 1, can stream, option suggested by Jon Skeet
        //https://dev59.com/w3M_5IYBdhLWcg3wn0lO#1300116
        var result1 = persons.
            DistinctBy(m => new {m.FirstName, m.LastName});

        //option 2, cannot stream, but does reference to DistinctBy
        //https://dev59.com/w3M_5IYBdhLWcg3wn0lO#4158364
        var result2 = persons.
            GroupBy(m => new { m.FirstName, m.LastName }).
            Select(group => group.First());
    }

    class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public string Address { get; set; }
    }

    private static List<Person> Setup()
    {
        var p1 = new Person
        {
            FirstName = "John",
            LastName = "Doe",
            Address = "USA"
        };

        var p2 = new Person
        {
            FirstName = "John",
            LastName = "Doe",
            Address = "Canada"
        };

        var p3 = new Person
        {
            FirstName = "Jane",
            LastName = "Doe",
            Address = "Australia"
        };

        var persons = new List<Person>();
        persons.Add(p1);
        persons.Add(p2);
        persons.Add(p3);

        return persons;
    }
}

public static class LinqExtensions
{
    public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
    {
        HashSet<TKey> knownKeys = new HashSet<TKey>();
        foreach (TSource element in source)
        {
            if (knownKeys.Add(keySelector(element)))
            {
                yield return element;
            }
        }
    }
}

1
Darkknight的答案可行且更简单,这正是我所寻找的。 - user3508811
@user3508811:Darkknight提供了第二个选项。它不需要任何外部依赖,但有点晦涩难懂。对于不熟悉LINQ的休闲程序员来说,它并不明显地在执行Distinct操作。Jon Skeet还提出了第一种选择,支持流式处理。根据数据大小的不同,这可能会很有用。语法也更加简洁。 - Victor Zakharov

0

您需要使用GroupBy(),它将创建一个IEnumerable<IGrouping<TKey, TElement>>,您可以对其进行迭代。您可以通过group.First()或通过某种聚合函数访问记录。


你能提供一个具体的示例吗?这会非常有帮助。 - user3508811
请参考DarkKnight的回答。 - Chris Berger

0

您可以使用多个链接的where条件。如果您正在进行数据库调用,请确保它是IQueryable类型。以下是一个示例:

List<SomeClass> c = new List<SomeClass>();
 var result = c.Where(x => x.ID == 4).Distinct().Where(y => y.Name == "foo").Distinct();

0

您可以实现IEqualityComparer并在Distinct()方法中使用它,而不是默认值。如果您例如实现了DataTestPlansComparer,则可以像以下示例一样使用:

DataTestPlans_DataID_ProductID = DataTestPlans.Where(c => c.DataID == DataID_ProductID_Record.DataID && c.ProductID == DataID_ProductID_Record.ProductID).Distinct(new DataTestPlansComparer());

注意,您的自定义比较器应作为参数传递给Distinct()方法。

在您的情况下可以是:

        public class DataTestPlanComparer : IEqualityComparer<DataTestPlan>
        {
            public bool Equals(DataTestPlan x, DataTestPlan y)
            {

                if (Object.ReferenceEquals(x, y)) return true;

                if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
                    return false;

                return x.DataID == y.DataID && x.ProductID == y.ProductID;
            }


            public int GetHashCode(DataTestPlan dataTestPlan)
            {
                if (Object.ReferenceEquals(dataTestPlan, null)) return 0;

                int hashDataTestPlanDataID = dataTestPlan.DataID == null ? 0 : dataTestPlan.DataID.GetHashCode();

                int hashDataTestPlanProductID = dataTestPlan.ProductID.GetHashCode();

                return hashDataTestPlanDataID ^ hashDataTestPlanProductID;
            }
        }

请按照MSDN指南实现IEqualityComparer。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接