如何从多个列表中选择不同的和有序的数据到通用列表中?

时间:2016-06-29 18:00:04

标签: c# linq generic-list

我有几个通用列表,其中包含一些共享和一些唯一数据。它们包含相同类的数据,但使用不同的参数(单位)填充。因此,所有通用列表都属于这种类型:List<PriceVarianceData>

我想对这些通用列表做些什么,是从它们中提取它们包含的不同数据的子集,然后订购合并列表。

更具体地说,要查询的列表具有以下结构:

public class PriceVarianceData
{
    public String Unit { get; set; }
    public String ShortName { get; set; }
    public String ItemCode { get; set; }
    public String Description { get; set; }
    public String PriceWeek { get; set; }
    public String Week { get; set; }
    public String Price { get; set; }
    public String Variance { get; set; }
    public String VarianceAverage { get; set; }
    public int RegionOrder { get; set; }
    public int ContractPrice { get; set; }
}

...我想要提取数据的通用列表具有以下结构:

public class PriceVarianceSupersetDisplayData
{
    public String ShortName { get; set; }
    public String ItemCode { get; set; }
    public String Description { get; set; }
}

单位将具有一些相同的ShortName + ItemCode + Description值,我只想要这些值的唯一组合 - 应该没有ShortName + ItemCode + Description的重复,但是如果它们的任何值不同,它们是被认为是独特/独特的。因此,在订购后,提取的数据应如下所示:

SHORTNAME   ITEMCODE    DESCRIPTION
---------   --------    -----------
Fakeroo     001         Stratoblaster
Fender      001         Stratocaster
Gibson      001         335
Gibson      001         SG
Fender      002         Telecaster
Gibson      002         Les Paul
Carvin      003         Knife
Carvin      003         L6S

我[我想]我知道我需要的是LINQ查询;在伪代码中,类似于:

List<PriceVarianceSupersetDisplayData> displayDataAmalgamated = select distinct ShortName, ItemCode, Description from craftworksPVDList, chophousePVDList, gordonbierschPVDList, oldchicagoPVDList, oldchifranchisePVDList, rockbottomPVDList order by ItemCode then by ShortName, then by Description

...但不知道如何将其从伪代码转换为真正的LINQ。

更新

user3185569和Zoran Horvat的答案的组合似乎有效,除了我显然没有得到明确的价值观。我的第一个线索是最终通用列表中的条目数量似乎太高了。

然后我查看了列表中的前两个条目,它们(或者至少看起来)是相同的:

enter image description here

这是我正在使用的代码;如上所述,它是前两个答案的组合:

private List<PriceVarianceSupersetDisplayData> GetSharedDisplayDataForAll()
{
    Func<PriceVarianceData, PriceVarianceSupersetDisplayData> selector =
        (p => new PriceVarianceSupersetDisplayData()
        {
            ShortName = p.ShortName,
            ItemCode = p.ItemCode,
            Description = p.Description
        });

    List<PriceVarianceSupersetDisplayData> displayDataAmalgamated =
            craftworksPVDList.Concat(chophousePVDList)
                            .Concat(chophousePVDList)
                            .Concat(gordonbierschPVDList)
                            .Concat(oldchicagoPVDList)
                            .Concat(oldchifranchisePVDList)
                            .Concat(rockbottomPVDList).Select(selector)
                            .Distinct()
                            .OrderBy(x => x.ItemCode)
                            .ThenBy(x => x.ShortName)
                            .ThenBy(x => x.Description).ToList();

    return displayDataAmalgamated;
}

为什么Distinct()会返回重复的值?

3 个答案:

答案 0 :(得分:2)

方法1:修改模型

首先实施EqualsGetHashCode。然后,您可以add将所有列表添加到一个列表中,select使用三个键并使用Distinct删除重复项,并使用OrderBy - ThenBy进行排序:< / p>

public class PriceVarianceSupersetDisplayData
{
    public String ShortName { get; set; }
    public String ItemCode { get; set; }
    public String Description { get; set; }

    public override bool Equals(object obj)
    {
        var pv = obj as PriceVarianceSupersetDisplayData;

        if (pv == null)
            return false;

        return this.ShortName == pv.ShortName
            && this.ItemCode == pv.ItemCode
            && this.Description == pv.Description;
    }

    public override int GetHashCode()
    {
        return 0;
    }
}

Func<PriceVarianceData, PriceVarianceSupersetDisplayData> selector =
                (p => new PriceVarianceSupersetDisplayData()
                {
                    ShortName = p.ShortName,
                    ItemCode = p.ItemCode,
                    Description = p.Description
                });

List<PriceVarianceSupersetDisplayData> results =
            craftworksPVDList.Concat(chophousePVDList)
                            .Concat(gordonbierschPVDList)
                            .Concat(oldchicagoPVDList)
                            .Concat(oldchifranchisePVDList)
                            .Concat(rockbottomPVDList).Select(selector).Distinct()
                            .OrderBy(x=> x.ItemCode).ThenBy(x=> x.ShortName)
                            .ThenBy(x=> x.Description).ToList();

方法2:不修改模型

(无需通过使用Equals的平等来实施GetHashCodeTuple

List<PriceVarianceSupersetDisplayData> results = 
        craftworksPVDList.Concat(chophousePVDList)
                        .Concat(gordonbierschPVDList)
                        .Concat(oldchicagoPVDList)
                        .Concat(oldchifranchisePVDList)
                        .Concat(rockbottomPVDList).Select(x=> Tuple.Create(x.ShortName, x.ItemCode, x.Description))
                        .Distinct().OrderBy(x=> x.Item2).ThenBy(x=> x.Item1).ThenBy(x=> x.Item3)
                        .Select(t=> new PriceVarianceSupersetDisplayData()
                        {
                            ShortName = t.Item1,
                            ItemCode = t.Item2,
                            Description = t.Item3
                        }).ToList();

答案 1 :(得分:1)

如果您希望构建另一个列表,其中只包含来自所有部分列表的不同数据,那么您可以通过使用Concat LINQ方法将它们连接在一起,然后最后使用Distinct LINQ方法来轻松实现:

list1.Concat(list2).Concat(list3)...Concat(listN).Distinct();

这假定类是值类型。既然您正在使用非常简单的类,我建议您在其中实现值类型语义,然后这种列表操作将变得微不足道。

添加值类型语义意味着重写GetHashCode,Equals,add operator ==和operator!=并且最好使用自己的Equals(T)实现IEnumerable。完成所有这些,正如我所说,列表操作将变得微不足道。

可以在最后添加对数据进行排序,例如:

list1
    .Concat(list2)
    .Concat(list3)
    ...
    .Concat(listN)
    .Distinct()
    .OrderBy(x => x.ItemCode)
    .ThenBy(x => x.ShortName)
    .ThenBy(x => x.Description);

答案 2 :(得分:1)

如果您不想打扰Equals / GetHashCode覆盖或实施IEqualityComparer<PriceVarianceSupersetDisplayData,这是让Distinct在其他答案中正常工作所必需的,最简单的是使用中间匿名类型投影(因为编译器自动为匿名类型实现正确的按值语义比较),如下所示:

var displayDataAmalgamated =
    new[] { craftworksPVDList, chophousePVDList, gordonbierschPVDList, oldchicagoPVDList, oldchifranchisePVDList, rockbottomPVDList }
    .SelectMany(list => list.Select(item => new { item.ShortName, item.ItemCode, item.Description }))
    .Distinct()
    .Select(item => new PriceVarianceSupersetDisplayData { ShortName = item.ShortName, ItemCode = item.ItemCode, Description = item.Description })
    .OrderBy(item => item.ShortName).ThenBy(item => item.ItemCode)
    .ToList();

或使用group by的查询语法:

var displayDataAmalgamated = (
    from list in new[] { craftworksPVDList, chophousePVDList, gordonbierschPVDList, oldchicagoPVDList, oldchifranchisePVDList, rockbottomPVDList }
    from item in list
    group item by new { item.ShortName, item.ItemCode, item.Description } into g
    orderby g.Key.ShortName, g.Key.Description
    select new PriceVarianceSupersetDisplayData { ShortName = g.Key.ShortName, ItemCode = g.Key.ItemCode, Description = g.Key.Description }
    ).ToList();