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。我想保留第一个,但去掉所有剩余的价格。

LINQ迭代IEnumerable并将重复项设置为null

方法:

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();