我有几个通用列表,其中包含一些共享和一些唯一数据。它们包含相同类的数据,但使用不同的参数(单位)填充。因此,所有通用列表都属于这种类型: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的答案的组合似乎有效,除了我显然没有得到明确的价值观。我的第一个线索是最终通用列表中的条目数量似乎太高了。
然后我查看了列表中的前两个条目,它们(或者至少看起来)是相同的:
这是我正在使用的代码;如上所述,它是前两个答案的组合:
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()会返回重复的值?
答案 0 :(得分:2)
首先实施Equals
和GetHashCode
。然后,您可以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();
(无需通过使用Equals
的平等来实施GetHashCode
或Tuple
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();