【问题标题】:Remove KeyValue from ObservableCollection most effective way?从 ObservableCollection 中删除键值最有效的方法?
【发布时间】:2012-03-31 00:20:54
【问题描述】:

我有以下代码从集合中删除组。从技术上讲,不应该有重复,但无论如何它都会删除所有内容。 LINQ to .Remove.Where.. 有什么技巧吗?

public void DeleteGroup(KeyValuePair<int, string> group)
            {
                while (this.Groups.Any(g => g.Key.Equals(group.Key)))
                {
                    var groupToRemove = this.Groups.First(g => g.Key.Equals(group.Key));
                    this.Groups.Remove(groupToRemove);
                }

            }

【问题讨论】:

  • 你可以试试this,用key代替value就行了

标签: c# .net linq


【解决方案1】:

假设您正在传递具有相同键和相同值的 KeyValuePair,这是使用 ObseravableCollection 可能最有效的方式。

public void DeleteGroup2(KeyValuePair<int, string> group)
{
    Groups.Remove(group);
}

之所以有效,是因为 KeyValuePair 是一个结构,当应用重载运算符 == 时,它会比较结构的 Key 和 Value 数据成员。

同样,如果您传入 Groups obserabableCollection 中包含的完全相同的键和值,这将正常工作...如果值不匹配,它将无法正常工作。

在幕后,ObserableCollection 几乎是一个列表,因此它必须遍历执行 == 运算符的每个项目。您发布的代码也是如此。仅仅因为它使用 LINQ 并不意味着它更有效。它不像 LINQ where 子句使用任何索引,就像使用 LINQ to SQL 一样。

public void DeleteGroup3(KeyValuePair<int, string> groupToDelete)
{
    var itemsToDelete =
        (
            from g in Groups
            where g.Key == groupToDelete.Key
            select g
        );

    foreach (var kv in itemsToDelete)
    {
        Groups.Remove(kv);
    }
}

如果您想保证删除所有项目,即使是具有重复键的项目,这可能是使用 linq 最有效的方法。

public void DeleteGroup4(KeyValuePair<int, string> group)
{
    List<int> keyIndexes = new List<int>();
    int maxIndex = Groups.Count;
    for (int i = 0; i < maxIndex; i++)
    {
        if (Groups[i].Key == group.Key)
        {
            keyIndexes.Add(i);
        }
    }

    int indexOffset = 0;
    foreach (int index in keyIndexes)
    {
        Groups.RemoveAt(index - indexOffset);
        indexOffset++;
    }
}

如果您有多个具有相同键的项目,或者您不知道与原始键完全相同的键值对,这应该是所有项目中性能最好的。

我相信您的 DeleteGroup 方法对于外部 Any while 循环是 2N^2...N 的 BIG O,对于第一个循环是 N,对于删除是 N。将外部循环乘以内部的总和,得到 2N^2

DeleteGroup2 是 N 中的 BIG O,并且在所有这些中具有最佳性能。缺点是您需要知道 Key 和 Value 而不仅仅是 Key。它也只会删除它找到的第一个项目。它不会删除具有相同 Key 和相同 Value 的重复项。

删除组 3 是 N + N^2 的大 O。 N 为选择。更糟糕的情况是您的密钥在那里 N 次,因此 N^2 用于删除。

DeleteGroup4 是 2N 的 BIG O。 N 来查找索引,在最坏的情况下,如果所有项目都具有相同的键,那么它的 N 删除它们中的每一个,因为 RemoveAtIndex 是 1 的大 O。如果你只知道键并且你有可能有多个项目具有相同的 Key。

如果您知道您不会有重复的项目,我会使用 DeleteGroup2。如果您有重复的可能性,DeleteGroup4 应该具有最佳性能。

附带说明,如果没有重复项并且您不一定知道 Key 和 Value,您仍然可以使用 DeleteGroup2 的最佳性能选项,但创建一个名为 KeyValueIntString 的类,该类具有 Key 和 Value 的属性。然后覆盖 IsEquals 方法,使其仅比较 Key 属性,这与比较 Key 和 Value 数据成员的 KeyValue 结构不同。然后您可以使用 ObserableCollection.Remove 方法,而不必担心知道存储的值。 IE。您可以传入设置了 Key 的 KeyValueIntString 实例,但您不必担心设置 Value 属性。

评论后我决定添加最佳可读性方法,尽管它的性能确实更差。有一个 N^4 的大 O。 N 代表 select,N 代表 ToList,N 代表 ForEach,N 代表 Remove。

public void DeleteGroup5(KeyValuePair<int, string> groupToDelete)
{
    (
        from g in Groups
        where g.Key == groupToDelete.Key
        select g
    ).ToList().ForEach(g => Groups.Remove(g));
}

【讨论】:

  • 哇!这样的回答。我正在寻找更短的解决方案 - 确保使用迭代的 LINQ。这是关于可读性/可维护性的。我的收藏很少有超过 1-2 个项目,并且几乎永远不会调用删除操作 :) 我只是想以最短和最干净的方式编写它。 DeleteGroup2 应该可以工作!
  • 在 1-2 项的情况下,我会考虑可读性。如果您有 1000 个或更多项目,我会选择性能。在很多代码审查中,我看到使用 LINQ 只是因为它很酷而且很新,并且会导致非常糟糕的性能,除非您知道在应用或不应用延迟加载时它是如何工作的。例如,在对整个表使用 LINQ 2 SQL 时使用 ToList 方法并在代码中应用 where 子句会导致糟糕的性能,因为没有使用主键、索引和外键。所有比较都在客户端或 Web 服务端完成。无论如何,我的 2 美分。
  • 关于使用 LINQ 时的可读性与性能。您只需要知道如何以及何时应用它。
  • 当然。就 DB 而言,我对 Linq 很满意。我正在尝试学习编写简短清晰代码的最有效方法。
  • 如果您最关心可读性,请考虑以下内容: public void DeleteGroup5(KeyValuePair groupToDelete) { ( from g in Groups where g.Key == groupToDelete.Key select g ).ToList ().ForEach(g => Groups.Remove(g)); } 它使用 lamda 表达式来表示 Remove Item。它有一个 N^3 的大 O。 N 表示 ToList * N 表示 ForEach,N 表示 Remove。这又是更糟糕的情况,物品在那里 N 次。
猜你喜欢
  • 2019-08-04
  • 2014-09-30
  • 2016-07-28
  • 2011-06-09
  • 1970-01-01
  • 2015-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多