LINQ迭代IEnumerable并将重复项设置为null
本文关键字:设置 null 迭代 IEnumerable LINQ | 更新日期: 2023-09-27 18:24:11
我有一个IEnumerable
IEnumerable<Pets> pets;
它由组成
public string Name { get; set; }
public string Other { get; set; }
public decimal? Price { get; set; }
我想迭代一遍,找到所有重复的价格,并将这些重复的价格设置为null。
假设一只猫和一只狗的价格相同:10.55。我想保留第一个,但去掉所有剩余的价格。
方法:
1) 删除重复项(我建议):
var filtered = pets.GroupBy(pet => pet.Price).Select(group => group.First());
2) 排序&evalute-根据需要设置null来代替重复项(您确定要设置null而不是像1中那样删除吗?)。
var newPets = pets.OrderBy(per => pet.Price).ToList();
if (!newPets.Any()) return newPets;
var last = 0;
for (var i = 1; i < newPets.Count; i++)
{
if (newPets[i].Price == newPets[last].Price) newPets[i] = null;
else last = i;
}
return newPets;
我认为在这种情况下排序就足够了:自定义迭代中的O(n * log n) + O(n)
对O(n^2)
搜索每个元素的重复项。
3) 经典方式(无排序,最慢)
var newPets = pets.ToList();
for (var i = 0; i < newPets.Count; i++)
{
if (newPets[i] == null) continue;
var price = newPets[i].Price;
for (var j = i + 1; j < newPets.Count; j++)
{
if (newPets[j].Price == price) newPets[j] = null;
}
}
正如D Stanley所注意到的(但我错过了),您可能必须将Price
设置为null
,而不是整个记录。然后简单地将其更改为decimal?
,然后写入newPets[i].Price = null;
,而不是将整个记录置空。
首先,decimal
不能为null,所以我会把它当作decimal?
类型来回答,这样你就可以理解这个过程了。
Linq用于查询,而不是更新。您可以在原始集合的基础上投影一个新集合,但foreach
可能更合适:
// list to keep tack of found prices
var prices = new List<decimal>();
foreach(Pet pet in pets)
{
if(prices.Contains(pet.Price.Value))
// price was found - set this one to null
pet.Price = null;
else
// add to the list of "found" prices
prices.Add(pet.Price.Value);
}
public class Pet
{
public string Name { get; set; }
public string Other { get; set; }
public decimal? Price { get; set; }
}
请注意,价格现在可以为空(decimal?
)
return pets
.OrderBy(x => x.Name)
.GroupBy(x => x.Price)
.OrderBy(x => x.Key)
.SelectMany(x => (new[] { x.First() }).Union(x.Skip(1).Select(n => new Pet { Name = n.Name, Other = n.Other, Price = null })))
.ToList();