C#3.0:需要返回列表中的副本<&燃气轮机;
我有一个C#中的对象列表,我需要一种方法返回那些在列表中被视为重复的对象。我不需要独特的结果集,我需要从存储库中删除的那些项目的列表 在本例中,假设我有一个“汽车”类型的列表,我需要知道这些汽车中的哪些与列表中的另一辆颜色相同。以下是列表中的汽车及其颜色属性:C#3.0:需要返回列表中的副本<&燃气轮机;,c#,linq,lambda,iequalitycomparer,C#,Linq,Lambda,Iequalitycomparer,我有一个C#中的对象列表,我需要一种方法返回那些在列表中被视为重复的对象。我不需要独特的结果集,我需要从存储库中删除的那些项目的列表 在本例中,假设我有一个“汽车”类型的列表,我需要知道这些汽车中的哪些与列表中的另一辆颜色相同。以下是列表中的汽车及其颜色属性: Car1.Color = Red; Car2.Color = Blue; Car3.Color = Green; Car4.Color = Red; Car5.Color = Red; 对于本例,我需要结果(IEnumerabl
Car1.Color = Red;
Car2.Color = Blue;
Car3.Color = Green;
Car4.Color = Red;
Car5.Color = Red;
对于本例,我需要结果(IEnumerable、List或其他任何内容)包含Car4和Car5,因为我想从我的存储库或db中删除它们,这样我的存储库中每种颜色只有一辆车。任何帮助都将不胜感激。IEnumerable GetDuplicateColor(列出汽车)
IEnumerable<Car> GetDuplicateColors(List<Car> cars)
{
return cars.Where(c => cars.Any(c2 => c2.Color == c.Color && cars.IndexOf(c2) < cars.IndexOf(c) ) );
}
{
返回cars.Where(c=>cars.Any(c2=>c2.Color==c.Color&&cars.IndexOf(c2)
它的基本意思是“如果列表中有相同颜色和较小索引的汽车,则返回汽车”
不过,我对性能不太确定。我怀疑使用O(1)查找重复项的方法(如dictionary/hashset方法)可以更快地查找大型集合。创建新的
dictionary foundColors
和列表carsToDelete
然后你反复浏览你的原始汽车列表,如下所示:
foreach(Car c in listOfCars)
{
if (foundColors.containsKey(c.Color))
{
carsToDelete.Add(c);
}
else
{
foundColors.Add(c.Color, c);
}
}
然后,您可以删除FoundColor中的每辆车
通过在
if
语句中添加“delete record”逻辑,而不是创建一个新的列表,您可以获得一个小的性能提升,但是您对问题的措辞表明,您需要将它们收集到一个列表中 如果不进行实际编码,那么像这样的算法如何:
- 反复浏览
创建列表
词典
- 遍历
删除词典
大于1的条目int
字典中的任何内容都有重复项。当然,您实际删除的第二部分是可选的。您只需遍历字典
,并查找要采取行动的>1即可
编辑:好的,我在瑞安的电脑上找到了,因为他实际上给了你密码 我昨天无意中编写了这个代码,当时我正试图编写一个“通过投影进行区分”。我包括了一个!当我不应该的时候,但这次正好:
public static IEnumerable<TSource> DuplicatesBy<TSource, TKey>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
HashSet<TKey> seenKeys = new HashSet<TKey>();
foreach (TSource element in source)
{
// Yield it if the key hasn't actually been added - i.e. it
// was already in the set
if (!seenKeys.Add(keySelector(element)))
{
yield return element;
}
}
}
这将按颜色对汽车进行分组,然后跳过每组的第一个结果,将每组的剩余结果平铺成单个序列
如果您对要保留哪一辆车有特殊要求,例如,如果该车具有Id
属性,并且您希望保留具有最低Id
的车,则您可以在其中添加一些订购,例如
var duplicates = from car in cars
group car by car.Color into grouped
from car in grouped.OrderBy(c => c.Id).Skip(1)
select car;
我的答案(按此顺序)来自以下受访者:乔·科霍恩、格雷格·比奇和乔恩·斯基特
我决定提供一个完整的例子,假设你有一个汽车颜色的静态列表。我相信下面的代码以一种优雅的方式(虽然不一定是超高效的)说明了问题的完整解决方案
#region SearchForNonDistinctMembersInAGenericListSample
public static string[] carColors = new[]{"Red", "Blue", "Green"};
public static string[] carStyles = new[]{"Compact", "Sedan", "SUV", "Mini-Van", "Jeep"};
public class Car
{
public Car(){}
public string Color { get; set; }
public string Style { get; set; }
}
public static List<Car> SearchForNonDistinctMembersInAList()
{
// pass in cars normally, but declare here for brevity
var cars = new List<Car>(5) { new Car(){Color=carColors[0], Style=carStyles[0]},
new Car(){Color=carColors[1],Style=carStyles[1]},
new Car(){Color=carColors[0],Style=carStyles[2]},
new Car(){Color=carColors[2],Style=carStyles[3]},
new Car(){Color=carColors[0],Style=carStyles[4]}};
List<Car> carDupes = new List<Car>();
for (int i = 0; i < carColors.Length; i++)
{
Func<Car,bool> dupeMatcher = c => c.Color == carColors[i];
int count = cars.Count<Car>(dupeMatcher);
if (count > 1) // we have duplicates
{
foreach (Car dupe in cars.Where<Car>(dupeMatcher).Skip<Car>(1))
{
carDupes.Add(dupe);
}
}
}
return carDupes;
}
#endregion
#区域搜索代理列表样本中的非唯一成员
公共静态字符串[]carColors=new[]{“红色”、“蓝色”、“绿色”};
公共静态字符串[]carStyles=new[]{“紧凑型”、“轿车”、“SUV”、“迷你面包车”、“吉普车”};
公车
{
公共汽车(){}
公共字符串颜色{get;set;}
公共字符串样式{get;set;}
}
public static List SearchForNonDistinctMembersInAList()
{
//正常情况下可以上车,但为了简洁起见,请在此申报
var cars=new List(5){new Car(){Color=carColors[0],Style=carStyles[0]},
新车(){Color=carColors[1],Style=carStyles[1]},
新车(){Color=carColors[0],Style=carStyles[2]},
新车(){Color=carColors[2],Style=carStyles[3]},
新车(){Color=carColors[0],Style=carStyles[4]};
列表卡片=新列表();
for(int i=0;ic.Color==carColors[i];
int count=cars.count(双匹配器);
如果(计数>1)//我们有重复项
{
foreach(汽车中的汽车dupe.Where(dupeMatcher.Skip(1))
{
卡片。添加(复制);
}
}
}
退货卡;
}
#端区
稍后我会回到这里,将这个解决方案与它的三个灵感进行比较,只是为了对比一下它们的风格。这很有趣。这里有一个稍微不同的Linq解决方案,我认为它可以让您更清楚地了解您要做的事情:
var s = from car in cars
group car by car.Color into g
where g.Count() == 1
select g.First();
它只是按颜色对汽车进行分组,剔除所有包含多个元素的组,然后将其余的组放入返回的IEnumerable中。公共静态IQueryable副本(此IEnumerable源),其中TSource:IComparable
{
if(source==null)
抛出新的ArgumentNullException(“源”);
返回source.Where(x=>source.Count(y=>y.Equals(x))>1.AsQueryable();
}+1-我没有想到跳过(1),因为提问者只想要副本。非常感谢你的回答Jon。帮助我优化在列表中查找重复项的方法。Resharper告诉我使用以下命令重构代码中的foreach:return source.Where(element=>!seenKeys.Add(keySelector(element))@科恩:嗯,我敢说这会奏效,但我不喜欢在谓词中包含副作用的想法。(这也会改变hashset创建的时间,但这是一件小事。)另一件事:返回具有相同键但第一个(循环顺序)的所有元素(因此,如果有3个重复项,则返回2个元素),这在我看来可能是一种奇怪的行为。要么返回所有副本,要么只返回一次密钥。。。
#region SearchForNonDistinctMembersInAGenericListSample
public static string[] carColors = new[]{"Red", "Blue", "Green"};
public static string[] carStyles = new[]{"Compact", "Sedan", "SUV", "Mini-Van", "Jeep"};
public class Car
{
public Car(){}
public string Color { get; set; }
public string Style { get; set; }
}
public static List<Car> SearchForNonDistinctMembersInAList()
{
// pass in cars normally, but declare here for brevity
var cars = new List<Car>(5) { new Car(){Color=carColors[0], Style=carStyles[0]},
new Car(){Color=carColors[1],Style=carStyles[1]},
new Car(){Color=carColors[0],Style=carStyles[2]},
new Car(){Color=carColors[2],Style=carStyles[3]},
new Car(){Color=carColors[0],Style=carStyles[4]}};
List<Car> carDupes = new List<Car>();
for (int i = 0; i < carColors.Length; i++)
{
Func<Car,bool> dupeMatcher = c => c.Color == carColors[i];
int count = cars.Count<Car>(dupeMatcher);
if (count > 1) // we have duplicates
{
foreach (Car dupe in cars.Where<Car>(dupeMatcher).Skip<Car>(1))
{
carDupes.Add(dupe);
}
}
}
return carDupes;
}
#endregion
var s = from car in cars
group car by car.Color into g
where g.Count() == 1
select g.First();
if (source == null)
throw new ArgumentNullException("source");
return source.Where(x => source.Count(y=>y.Equals(x)) > 1).AsQueryable<TSource>();