简体   繁体   English

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

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

I have several generic lists with some shared and some unique data in them. 我有几个通用列表,其中包含一些共享的数据和一些唯一的数据。 They contains data of the same class, but are populated using different params (Unit). 它们包含相同类的数据,但使用不同的参数(单元)填充。 So all of the generic lists are of this type: List<PriceVarianceData> 因此,所有通用列表都属于这种类型: List<PriceVarianceData>

What I want to do with these generic lists is to extract from them a subset of the distinct data they contain, and then order that amalgamated list. 我要对这些通用列表进行的操作是从它们中提取它们包含的独特数据的子集,然后对合并后的列表进行排序。

To be more specific, the lists to be queried have this structure: 更具体地说,要查询的列表具有以下结构:

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; }
}

...and the generic list into which I want to extract the data has this structure: ...并且我要将数据提取到的通用列表具有以下结构:

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

The Units will have some of the same ShortName + ItemCode + Description values, and I only want unique combinations of those values - there should be no duplicates of ShortName + ItemCode + Description, however if they differ in any value, they are to be considered unique/distinct. 单位将具有一些相同的ShortName + ItemCode + Description值,我只希望这些值的唯一组合-不应重复ShortName + ItemCode + Description,但是,如果它们的值不同,则应将它们考虑在内独特/不同。 So data extracted should, after ordering, look like: 因此,提取的数据应在订购后如下所示:

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

I [think I] know that what I need here is LINQ query; 我(认为我)知道这里需要的是LINQ查询; in pseudocode, something like: 用伪代码,类似于:

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

...but don't know precisely how to turn that from pseudocode into real LINQ. ...但是不知道如何将其从伪代码转换为真正的LINQ。

UPDATE UPDATE

A combination of user3185569's and Zoran Horvat's answers seems to work, except that I am apparently not getting distinct values. user3185569的答案和Zoran Horvat的答案结合使用似乎很奏效,只是我显然没有得到不同的价值。 My first clue was that the number of entries in the final generic list seemed to be too high. 我的第一个线索是,最终通用列表中的条目数量似乎太高了。

Then I looked at the first two entries in the list, and they are (or at least seem to be) identical: 然后,我查看了列表中的前两个条目,它们是(或至少看起来是相同的):

在此处输入图片说明

This is the code I'm using; 这是我正在使用的代码; as mentioned, it is a combination of the first two answers provided: 如前所述,它是前两个答案的组合:

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;
}

Why does Distinct() return duplicated values? 为什么Distinct()返回重复的值?

Method 1 : Modifying the model 方法1:修改模型

Implement Equals and GetHashCode First. 首先实现EqualsGetHashCode Then, You can add all the lists to one list, select the three keys and use Distinct to remove duplicates and OrderBy - ThenBy for ordering: 然后,您可以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();

Method 2 : Without modifying the model 方法2:不修改模型

(No need to implement Equals or GetHashCode by making using of Tuple 's Equality) (无需通过使用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();

If you wish to construct another list with only distinct data from all partial lists, then you can do that easily by joining them together using Concat LINQ method, and then using the Distinct LINQ method in the end: 如果您希望仅使用所有部分列表中的不同数据来构造另一个列表,则可以通过使用Concat LINQ方法将它们结合在一起,然后最后使用Distinct LINQ方法来轻松地做到这一点:

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

This assumes that classes are value types. 假设类是值类型。 Since you're working with very simple classes, I would suggest you to implement value type semantics into them, and then this kind of list manipulation will become trivial. 由于您使用的是非常简单的类,因此建议您在它们中实现值类型语义,然后这种列表操作将变得很简单。

Adding value type semantics means to override GetHashCode, Equals, add operator == and operator != and preferably implement IEnumerable with its own Equals(T). 添加值类型语义意味着重写GetHashCode,Equals,添加运算符==和运算符!=,并最好使用其自己的Equals(T)实现IEnumerable。 With all that done, as I said, list manipulation will become trivial. 正如我所说,完成所有这些操作后,列表操作将变得微不足道。

Sorting the data can be added at the very end, like: 排序数据可以在最后添加,例如:

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

If you don't want to bother with Equals / GetHashCode overrides or implementing IEqualityComparer<PriceVarianceSupersetDisplayData , which are needed to make Distinct work correctly in other answers, the easiest is to use intermediate anonymous type projection (because the compiler implements automatically the correct compare by value semantics for anonymous types) like this: 如果您不想打扰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();

or using query syntax with group by : 或对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.

相关问题 如果由包括的实体订购,如何在Linq Select Distinct中订购? - How can I order in Linq Select Distinct if ordered by an Included entity? 如何从通用日期列表中选择不同的(按唯一月份/年份)? - How would I select distinct (by unique month/year) from a generic list of dates? 如何使用 LINQ 从 DataTable 中获取不同的、有序的名称列表? - How do I get a distinct, ordered list of names from a DataTable using LINQ? 从多个不同的列表创建通用列表 - Create a generic list from multiple different lists 如何创建列出数据库中数据的通用实现? - How can I create a generic implementation that lists data from my database? 如何组合来自两个通用列表的数据并将该合并分配为 DataGridView 的数据源? - How can I combine data from two generic lists and assign that amalgamation as the datasource of a DataGridView? 如何在其他类型的列表中选择所有不同的字符串? - How do I select all distinct strings in a list of lists of another type? 如何:选择不同的对象 <T> 来自多个列表 <T> 具有1个或多个相同类型的属性 - How to: Select Distinct objects<T> from multiple Lists<T> with 1 or more properties of same type 如何从列表中删除列表? - How can i remove Lists from List? 使用LINQ从列表中选择不同的数据 - select the distinct data from list using LINQ
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM