繁体   English   中英

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

[英]How can I select distinct and ordered data into a generic list from multiple lists?

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

UPDATE

user3185569的答案和Zoran Horvat的答案结合使用似乎很奏效,只是我显然没有得到不同的价值。 我的第一个线索是,最终通用列表中的条目数量似乎太高了。

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

在此处输入图片说明

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

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()返回重复的值?

方法1:修改模型

首先实现EqualsGetHashCode 然后,您可以add所有列表add到一个列表中, select三个键,然后使用Distinct删除重复项并使用OrderBy - ThenBy进行排序:

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:不修改模型

(无需通过使用TupleEquals实现EqualsGetHashCode

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

如果您希望仅使用所有部分列表中的不同数据来构造另一个列表,则可以通过使用Concat LINQ方法将它们结合在一起,然后最后使用Distinct LINQ方法来轻松地做到这一点:

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

假设类是值类型。 由于您使用的是非常简单的类,因此建议您在它们中实现值类型语义,然后这种列表操作将变得很简单。

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

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

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

如果您不想打扰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();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM