[英]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。
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()返回重复的值?
Implement Equals
and GetHashCode
First. 首先实现
Equals
和GetHashCode
。 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();
(No need to implement Equals
or GetHashCode
by making using of Tuple
's Equality) (无需通过使用
Tuple
的Equals
实现Equals
或GetHashCode
)
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.