【问题标题】:Adding IEnumerable<Type> to IList<Type> where IList doesn't contain primary key - LAMBDA将 IEnumerable<Type> 添加到 IList<Type> 其中 IList 不包含主键 - LAMBDA
【发布时间】:2011-11-22 17:17:32
【问题描述】:

我有一个IList&lt;Price&gt; SelectedPrices。我还有一个IEnumerable&lt;Price&gt;,稍后会被检索到。我想将后者的所有内容添加到前者,其中前者不包含后者中定义的主键。比如:

IList&lt;Price&gt; 包含 Price.ID = 1Price.ID = 2IEnumerable&lt;Price&gt; 包含 Price.ID = 2Price.ID = 3Price.ID = 4。使用 lambda 添加这些项目以便我最终得到包含 4 个唯一价格的 IList 的最简单方法是什么?我知道我必须在IList 上调用ToList() 才能访问AddRange() 方法,以便我可以一次添加多个项目,但是如何仅选择该列表中不存在的项目可枚举的?

【问题讨论】:

  • (请注意,要使尖括号正确显示,它们必须被格式化为代码,无论是反引号还是四个空格缩进。{}编辑器中的按钮将对所选文本执行正确的操作,将其格式化为代码)

标签: c# .net lambda ienumerable ilist


【解决方案1】:

我知道我必须在 IList 上调用 ToList() 才能访问 AddRange() 方法

这实际上是不安全的。这将创建一个 List&lt;T&gt;,因此您不会将这些项目添加到您原来的IList&lt;T&gt;。您需要一次添加一个。

最简单的选择就是循环并使用包含:

var itemsToAdd = enumerablePrices.Where(p => !SelectedPrices.Any(sel => sel.ID == p.ID));
foreach(var item in itemsToAdd)
{
    SelectedPrices.Add(item);
}

但是,这本质上是二次的,所以如果集合非常大,它可能会很慢。根据集合的大小,实际上最好提前构建一组 ID:

var existing = new HashSet<int>(SelectedPrices.Select(p => p.ID));
var itemsToAdd = enumerablePrices.Where(p => !existing.Contains(p.ID));
foreach(var item in itemsToAdd)
{
    SelectedPrices.Add(item);
}

如果您的集合 (SelectedPrices) 很大,这将防止例程变为二次函数。

【讨论】:

  • 我明白了。所以 Where -> Any 选择器将映射两个列表中的所有 ID,从而强制二次?无论如何,第二段代码似乎都一样可读。
  • @user623647 是 - 对于 n 个“SelectedPrice”实例,.Any 将是 O(n)。这使得可枚举中的 N 个元素和列表中的 M 个元素的 O(n*m)。相反,第二个选项变为线性的,但初始设置散列集的开销更高。如果集合总是很小,我只会使用第一个 - 但如果 SelectedPrices 可能很大,第二个会阻止你去二次。
【解决方案2】:

你可以试试:

var newPrices = prices.Where(p => !SelectedPrices.Any(sp => sp.ID == p.ID));
foreach(var p in newPrices)
    SelectedPrices.Add(p);

我知道我必须在 IList 上调用 ToList() 才能访问 AddRange() 方法,以便我可以一次添加多个项目

ToList 将创建List&lt;Price&gt; 的新实例,因此您将修改另一个列表,而不是原来的列表...不,您需要逐个添加项目。

【讨论】:

  • 啊,有道理。我希望能摆脱 foreach,但这是完美的。谢谢。
【解决方案3】:

请尝试 yourEnumerable.Where(x =&gt; !yourList.Any(y =&gt; y.ID == x.ID)) 选择问题的部分。

【讨论】:

    【解决方案4】:

    如果您想在现有列表中添加新元素并以最高效的方式执行此操作,您可能应该以传统方式执行此操作。像这样:

        IList<Price> selectedPrices = ...;
        IEnumerable<Price> additionalPrices = ...;
    
        IDictionary<int, Price> pricesById = new Dictionary<int, Price>();
    
        foreach (var price in selectedPrices) 
        { 
            pricesById.Add(price.Id, price); 
        }
    
    
        foreach (var price in additionalPrices)
        {
            if (!pricesById.ContainsKey(price.Id))
            {
                selectedPrices.Add(price);
            }
        }
    

    【讨论】:

      猜你喜欢
      • 2010-11-30
      • 1970-01-01
      • 2018-05-21
      • 1970-01-01
      • 1970-01-01
      • 2011-09-17
      • 1970-01-01
      • 2020-04-03
      • 1970-01-01
      相关资源
      最近更新 更多