【问题标题】:Getting unique items from a list [duplicate]从列表中获取唯一项目[重复]
【发布时间】:2010-11-26 04:17:29
【问题描述】:

从列表中获取所有不同项目的最快/最有效的方法是什么?

我有一个List<string>,其中可能有多个重复项,并且只想要列表中的唯一值。

【问题讨论】:

  • 这个问题的标题具有误导性。选择唯一项目是关于选择列表中仅出现一次的项目,而不是选择每个不同的元素一次。给定["A", "B", "C", "C", "D", "D"],唯一项将返回["A","B"],而不同项将返回["A", "B", "C", "D"]
  • @EduardoPignatelli 相当挑剔,但这个问题可以毫不含糊地重新措辞。通常遇到的这个问题的意图是:“给定一个值列表,我如何在不重复任何值的情况下获得这些值的列表?”

标签: c# list unique


【解决方案1】:

您可以使用Distinct 方法返回不同项目的IEnumerable<T>

var uniqueItems = yourList.Distinct();

如果您需要以List<T> 形式返回的唯一项目序列,您可以添加对ToList 的调用:

var uniqueItemsList = yourList.Distinct().ToList();

【讨论】:

  • OP 正在寻找一种快速/高效的方法。这不是它。调用yourList.Distinct().ToList() 需要对可枚举进行两次完整迭代,此外还基于IEqualityComparer,它比GetHashCode 慢。
  • 这是否比 HashSet 更快/更高效?我不这么认为。不过,不必费心投反对票:-)
  • @Noldorin, @Vinay: 如果 OP 需要以List 形式返回的不同项目,那么他们需要调用ToList,无论他们是否使用Distinct 或构造一个 HashSet。话虽如此,在大多数情况下,HashSet 的性能可能比Distinct 更好。
  • @Noldorin:我知道这很旧,但它很容易在 Google 上显示,你错了(至少,从 .NET 4 开始 - 我还没有检查旧版本)。 yourList.Distinct().ToList() 执行一次枚举, new HashSet(yourList).ToList() 执行两次。 HashSet 和 Distinct 的内部 Set 类的实现几乎完全相同。它们都使用 GetHashCode,并且都使用 IEqualityComparers(它们必须这样做,因为相等的哈希码(通常)不能保证相等的对象)。
  • @Noldorin:性能基准如何支持或反对我所说的?您可以通过在 Reflector(或其他 .NET 反编译器)中调出 System.Linq.Enumerable.DistinctIterator 和 System.Linq.Set 来验证我所说的,与相对性能无关。
【解决方案2】:

使用HashSet<T>。例如:

var items = "A B A D A C".Split(' ');
var unique_items = new HashSet<string>(items);
foreach (string s in unique_items)
    Console.WriteLine(s);

打印

一种 乙 D C

【讨论】:

  • 必须同意;别人解决问题,你解决原因:)
  • A HashSet 不会维护任何排序,这可能是也可能不是 OP 的问题。
  • 谢谢大家,我不需要订购这些物品。这很好用。
【解决方案3】:

您可以使用 LINQ 中的Distinct 扩展方法

【讨论】:

    【解决方案4】:

    在 .Net 2.0 中,我很确定这个解决方案:

    public IEnumerable<T> Distinct<T>(IEnumerable<T> source)
    {
         List<T> uniques = new List<T>();
         foreach (T item in source)
         {
             if (!uniques.Contains(item)) uniques.Add(item);
         }
         return uniques;
    }
    

    【讨论】:

    • 使用比 List 更快的随机访问集合,例如 Dictionary 或 HashSet。因为目前,如果source 包含 100,000 个具有许多重复项的项目,那么在 100,000 次迭代中的每一次迭代中,您将扫描大约 100,000 个项目的列表,这意味着您正在扫描 100,000 * 100,000 项目的顺序。二次时间复杂度会变得很慢。
    【解决方案5】:

    除了 LINQ 的 Distinct 扩展方法之外,您还可以使用您的集合初始化的 HashSet&lt;T&gt; 对象。这很可能比 LINQ 方式更有效,因为它使用哈希码 (GetHashCode) 而不是 IEqualityComparer)。

    事实上,如果它适合您的情况,我会首先使用HashSet 来存储项目。

    【讨论】:

    • A HashSet 不会维护任何排序,这可能是也可能不是 OP 的问题。
    • @Luke: 即便如此,打电话给Distinct之后点餐就没有意义了...
    • @Luke:这个问题询问最快/最有效,并且不需要维护订单。
    • @Noldorin:为什么不呢? Distinct 应该/确实按顺序迭代列表(尽管我不确定这是否真的在任何规范中得到保证)。
    • @Luke:哦,我真的在考虑索引。无论如何,OP 中提到了效率,而没有提到顺序(尽管这是一个悬而未决的问题)-HashSet 是您想要获得良好性能的方法。
    猜你喜欢
    • 2011-10-19
    • 2017-07-06
    • 2020-09-21
    • 2019-08-01
    • 2013-06-12
    • 1970-01-01
    • 2016-08-24
    • 2012-10-05
    • 1970-01-01
    相关资源
    最近更新 更多