【问题标题】:Find Item in ObservableCollection without using a loop在 ObservableCollection 中查找项目而不使用循环
【发布时间】:2012-05-08 12:10:45
【问题描述】:

目前我有以下语法(列表是一个包含具有许多不同属性的对象的列表(其中标题是其中之一):

for (int i=0; i < list.Count; i++)
{
   if(title == list[i].Title)
   {
    //do something
   }
}

我怎样才能访问list[i].Title 而不必遍历我的整个收藏?由于我的列表往往会变得很大,这可能会影响我的程序的性能。

我的程序中有很多类似的语法(通过 for 循环和索引访问公共属性)。但我确信一定有更好更优雅的方式来做到这一点?

find 方法似乎是一个选项,因为我的列表包含对象。

【问题讨论】:

  • 您可以使用 linq,例如 Find,或者您可以实现自己的 Dictionary 并支持 INotifyCollectionChanged
  • 字典对键的查找速度非常快,但键必须是唯一的。由于标题不是唯一的,因此需要循环。优化类,确保Title得到;不马虎。如果对象具有内部主键,则使用该键覆盖 GetHashCode。

标签: c# wpf collections


【解决方案1】:

我不知道你是什么意思确切,但从技术上讲,这是不可能的没有循环。

您的意思可能是使用 LINQ,例如:

list.Where(x=>x.Title == title)

值得一提的是,没有跳过迭代,而是简单地包装到 LINQ 查询中。

希望这会有所帮助。

编辑

换句话说,如果您真的关心性能,请继续按照您现有的方式进行编码。否则,请选择 LINQ 以获得更简洁明了的语法。

【讨论】:

  • 所以基本上我的语法没问题?我只是想知道性能,因此我的问题。
  • 它通常比 LINQ 快,但正如您所看到的,它的代码行数要多得多,LINQ 的编写更加简洁。
  • 好的,谢谢,我想我会继续使用我的 for 语句,因为性能在我的程序中非常重要。
  • @Tigran 使用 LINQ 代替 for 循环不会以任何明显的方式降低性能(即使是速度测试)。
  • @YoryeNathan:这取决于情况,在这个具体的代码示例中,可能是。通常 LINQ 比较慢。
【解决方案2】:

Linq 来了:

var listItem = list.Single(i => i.Title == title);

如果没有与谓词匹配的项目,则会引发异常。或者,还有SingleOrDefault

如果你想要一个匹配标题的项目集合,有:

var listItems = list.Where(i => i.Title ==  title);

【讨论】:

  • 这是任何人想要找到一个符合特定标准的对象的答案。
  • 问题是关于性能,但您没有提及性能。是 nLogN 吗?
【解决方案3】:

如果您不需要索引,我必须将它用于添加条件

using System.Linq;

使用

if(list.Any(x => x.Title == title){
// do something here
}

这将告诉您是否有任何变量满足您的给定条件。

【讨论】:

    【解决方案4】:

    我建议将这些存储在哈希表中。然后,您可以使用键访问集合中的项目,这是一种更有效的查找。

    var myObjects = new Hashtable();
    myObjects.Add(yourObject.Title, yourObject);
    ...
    var myRetrievedObject = myObjects["TargetTitle"];
    

    【讨论】:

    • 你也可以考虑使用 Dictionary
    【解决方案5】:

    考虑创建一个索引。字典可以解决问题。如果您需要列表语义,子类化并将索引保​​留为私有成员...

    【讨论】:

      【解决方案6】:

      ObservableCollection 是一个列表,因此如果您不知道元素位置,则必须查看每个元素,直到找到预期的元素。

      可能的优化 如果您的元素已排序,请使用二进制搜索来提高性能,否则使用字典作为索引。

      【讨论】:

        【解决方案7】:

        您正在寻找 ObservableCollection 不是基于哈希的集合(如字典或哈希集)。最好的解决方案可能是从基于哈希的集合中派生并实现 INotifyCollectionChanged,这将为您提供与 ObservableCollection 相同的行为。

        【讨论】:

          【解决方案8】:

          好吧,如果您有 N 个对象并且需要获取所有对象的标题,则必须使用循环。如果你只需要标题并且你真的想改进它,也许你可以制作一个只包含标题的单独数组,这会提高性能。 在说这会损害性能之前,您需要定义可用的内存量和可以处理的对象量,并且无论如何解决方案都是改变程序的设计而不是算法。

          【讨论】:

          • 我会说在列表上使用二叉树正在改变算法而不是程序的设计
          【解决方案9】:

          也许这种方法可以解决问题:

          int result = obsCollection.IndexOf(title);
          

          IndexOf(T)
          搜索指定对象并返回整个 Collection 中第一次出现的从零开始的索引。

          (从集合继承)

          https://docs.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.observablecollection-1?view=netframework-4.7.2#methods

          【讨论】:

          • "Collection 从第一个元素开始向前搜索,到最后一个元素结束。" - 所以不是一个有效的答案
          【解决方案10】:

          一个 observablecollection 可以是一个 List

          {
              BuchungsSatz item = BuchungsListe.ToList.Find(x => x.BuchungsAuftragId == DGBuchungenAuftrag.CurrentItem.Id);
          }
          

          【讨论】:

          • "此方法执行线性搜索;因此,此方法是 O(n) 操作,其中 n 是 Count。" - 不是一个有效的答案
          猜你喜欢
          • 1970-01-01
          • 2012-02-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-10-11
          相关资源
          最近更新 更多