使用LINQ获取列表中匹配值的索引

6
我希望能够在一个BindingList(Of T)上运行LINQ查询,以返回列表对象成员等于特定值的索引。比如我有一个widget类的简单对象列表:
Public Class widget
    Public Property foo As Integer
    Public Property bar As String
End Class
Dim widgetList As BindingList(Of widget)

我希望能够查询列表,类似于以下内容:

Dim test As Integer = 5
Dim index = (From i In widgetList
             Where i.foo = test
             Select i.index).First

这样,索引包含第一个listItem的索引,其中widgetList.Item(index).foo = 5。最好的方法是什么?(或者我应该使用LINQ吗)

我看到了几种用于此操作的C#方法,但我对C#不够熟悉,无法理解如何在VB中使用它们。


就linq而言,C#和VB的语法大致相同。关于您的问题:在标题中,您正在询问匹配值(这意味着您希望有多个匹配项),但是在代码中,您使用.First,这意味着您仅从选择的结果中获取第一个项目。 - Marko Gresak
所以我做了 - 编辑以去除复数。谢谢 - Toby
2个回答

7
使用流畅语法,通过 LINQ 可以实现此操作,因为Select扩展方法有一种重载版本,可以让您获得项目的索引。尝试以下方法:
Dim test As Integer = 5
Dim query = widgetList.Select(Function(o,i) New With { .Widget = o, .Index = i}) _
                      .FirstOrDefault(Function(item) item.Widget.Foo = test)
If query Is Nothing
    Console.WriteLine("Item not found")
Else
    Console.WriteLine("Item found at index {0}", query.Index)
End If

Select 中,我使用 o 投射 Widget,并且参数 i 表示索引。接下来,我使用带有谓词的 FirstOrDefault 来评估 Foo(你也可以使用 Where 后跟 FirstOrDefault,但这样更短)。你应该使用 FirstOrDefault 而不是只使用 First,以防找不到任何项;如果没有找到任何内容,FirstOrDefault 将返回 null,而 First 会抛出异常。这就是为什么下一步是检查结果并确保它不为 null 的原因。


1

我也找到了一个有效的解决方案,如下所示,尽管我不确定这是比其他答案更好还是更差。

Dim index = Enumerable.Range(0, widgetList.Count) _
            .Where(Function(i) widgetList.Item(i).foo = test) _
            .First

1
这个可以工作,但是你引入了一个新的集合来与原始集合进行比较,这可能会导致性能变慢。从可读性的角度来看,对于原始集合进行操作更清晰。从性能的角度来看,代码必须生成范围内的n个项目来评估查询。 - Ahmad Mageed
@AhmadMageed,好人,谢谢,我会采纳你的答案 :) - Toby

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