如何在Observable Collection中搜索项目并获取其索引

11
public struct PLU
{ 
    public int ID { get; set; } 
    public string name { get; set; } 
    public double price { get; set; } 
    public int quantity {get;set;}
}

public static ObservableCollection<PLU> PLUList = new ObservableCollection<PLU>();

我有上述的ObservableCollection。现在我想要搜索PLUList中的ID,并像这样获取其索引:

int index = PLUList.indexOf();
if (index > -1)
{
    // Do something here
}
else
{
    // Do sth else here..
}

有什么快速的解决方法?

编辑:

假设已经向PLUList添加了一些项目,并且我想添加另一个新项目。 但在添加之前,我想检查列表中是否已存在ID。 如果存在,则希望将quantity加1。

5个回答

26

使用LINQ :-)

var q =  PLUList.Where(X => X.ID == 13).FirstOrDefault();
if(q != null) 
{
   // do stuff
}
else 
{
   // do other stuff
}

如果您想保持结构体,请使用此方法:

var q =  PLUList.IndexOf( PLUList.Where(X => X.ID == 13).FirstOrDefault() );
if(q > -1) 
{
   // do stuff
}
else 
{
   // do other stuff
}

这是一个结构体。你不能将其测试为空。 - A.R.
@user995387:我更倾向于使用类。 - Mithrandir
@Mithrandir 关于16字节限制的问题 - 需要引用来源。 - Jakub Konecki
@JakubKonecki 真的吗?那好,给你这个链接:https://msdn.microsoft.com/zh-cn/library/ms229017(v=vs.110).aspx - Mithrandir
1
通过先查找项目,然后再遍历整个列表来获取索引,对于大型列表或者代码在繁忙执行路径中运行会很慢。 - Sten Petrov
显示剩余4条评论

3

如果您想从列表中检索项目,只需使用LINQ:

PLU item = PLUList.Where(z => z.ID == 12).FirstOrDefault();

但是这将返回该项本身,而不是它的索引。你为什么需要索引呢?

另外,如果可能的话,应该使用class而不是struct。然后,您可以将itemnull进行测试,以查看是否在集合中找到了ID

if (item != null)
{
    // Then the item was found
}
else
{
    // No item found !
}

3
虽然这篇文章已经老旧并且已有答案,但对其他人仍可能有用,所以我在这里提供我的答案。
你可以创建类似于 List<T>.FindIndex(...) 方法的扩展方法:
public static class ObservableCollectionExtensions
{
    public static int FindIndex<T>(this ObservableCollection<T> ts, Predicate<T> match)
    {
        return ts.FindIndex(0, ts.Count, match);
    }

    public static int FindIndex<T>(this ObservableCollection<T> ts, int startIndex, Predicate<T> match)
    {
        return ts.FindIndex(startIndex, ts.Count, match);
    }

    public static int FindIndex<T>(this ObservableCollection<T> ts, int startIndex, int count, Predicate<T> match)
    {
        if (startIndex < 0) startIndex = 0;
        if (count > ts.Count) count = ts.Count;

        for (int i = startIndex; i < count; i++)
        {
            if (match(ts[i])) return i;
        }

        return -1;
    }
}

使用方法:

int index = PLUList.FindIndex(x => x.ID == 13);
if (index > -1)
{
    // Do something here...
}
else
{
    // Do something else here...
}

ObservableCollection 倾向于异步更改,这些扩展不是线程安全的。如果线程不是一个问题,那么这个答案比被接受的答案执行得更好。 - Sten Petrov
任何其他查找索引的方式同样不是线程安全的,程序员在搜索索引时需要注意线程安全。 - Eliahu Aaron
是的,但您的代码应考虑线程安全。col.FindIndex(match) 本身可能会出现问题。 - Sten Petrov

2

这是一个快速解决方案。

int findID = 3;
int foundID=  -1;
for (int i = 0; i< PLUList.Count; i++)
{
  if (PLUList[i].ID == findID)
  {
    foundID = i;
    break;
  }
}

// Your code.
if (foundID > -1) {
// Do something here
...

这个答案有几个问题:1)循环保护中的<=应该改为<,因为当循环到最后一次迭代时,会出现索引越界异常;2)需要检查PLUList[i].ID == findID - Strelok
@Strelok:你看,这就是为什么智能感知是邪恶的!我不能再简单地在文本框中输入了=)。无论如何,谢谢你的提示。 - A.R.
1
@Strelok:我的真正错误是匆忙发布了琐碎的答案! - A.R.

1

这只是一个普通的集合。您可以遍历它,检查ID并返回对象的索引。

int index = -1;

for(int i=0;i<PLUList.Count;i++) {
 PLU plu = PLUList[i];
 if (plu.ID == yourId) {
   index = i;
   break;
 }
}

if (index > -1) {
// Do something here
}
else {
// Do sth else here..
}

LINQ版本:

private void getIndexForID(PLUListint idToFind,ObservableCollection<PLU> PLUList) {
   PLU target = PLUList.Where( z => z.ID == yourID ).FirstOrDefault();
   return target == null ? -1 : PLUList.IndexOf ( target );
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接