在C#中获取列表中重复项的索引

5

我希望你能帮我翻译一下关于IT技术的内容。以下是需要翻译的内容:

我正在寻找一种方法,通过在列表中进行关键字搜索来获取所有元素的索引。例如,我的列表如下:

Hello World
Programming Rocks
Hello
Hello World
I love C#
Hello

现在我有一个字符串列表,我想获取所有包含“Hello World”的元素的索引。我尝试了以下方法,但它只返回符合搜索条件的第一个索引:
    for (int i = 0; i< searchInList.Count; i++)
        foundHelloWorld[i] = searchInList.IndexOf("Hello World");

有人知道如何做到这一点吗?
谢谢。

你是否在寻找包含任何重复内容的所有索引列表?大局是什么? - Chris Trombley
哈哈,这不是作业。我有一个列表,可能包含重复的条目。我想找到一种方法,在使用任何方法时都考虑到可能存在重复项,并给出所有索引。 - Ryan
所以你只是想知道列表中是否包含指定字符串的重复项,而不在乎索引? - Magnus
4个回答

9
searchInList.Select((value, index) => new {value, index})
    .Where(a => string.Equals(a.value, "Hello World"))
    .Select(a => a.index)

如果你想搜索的不仅仅是 "Hello World",你可以这样做:

searchInList.Select((value, index) => new {value, index})
    .Where(a => stringsToSearchFor.Any(s => string.Equals(a.value, s)))
    .Select(a => a.index)

如果你的老师允许使用LINQ,那么把它作为作业会很有趣 :) - user57508
我收到一个错误,提示无法隐式转换<int>到int。 - Ryan
它基本上就是你所拥有的。我只是像这样在你的代码上面声明了列表:List<int> searchInList= new List<int>(); - Ryan
等一下,我实际上把你的语句分配给了foundHelloWorld =。 - Ryan
你好世界并不是我需要索引的唯一术语。我有一个术语列表,需要在searchInList中搜索,并获取所有出现位置的索引,返回一个整数列表。 - Ryan
显示剩余6条评论

2

既然您知道要查找所有出现的内容,因此必须遍历整个列表,那么通过自己检查每个元素,相比使用IndexOf函数,您将获得更好的可读性:

var i=0;
foreach(var value in searchInList)
{
   if(value == "Hello World")
      foundHelloWorld.Add(i); //foundHelloWorld must be an IList

   i++;
}

您还可以使用 Linq Select 方法的一种重载,该方法将元素在源集合中的索引并入其中;这应该对有 Linq 经验的程序员来说非常易读(因此易于维护):

foundHelloWorld = searchInList
                     .Select((v,i)=>new {Index = i, Value = v})
                     .Where(x=>x.Value == "Hello World")
                     .Select(x=>x.Index)
                     .ToList();

上面的代码将列表转换为一个简单的匿名类型,该类型包含每个项目在原始列表中的位置。然后,它会将其筛选出匹配的元素,然后将索引(在过滤时未更改)投影到新的列表对象中。但是,所有这些转换都会使此解决方案的性能变慢,因为该语句将多次遍历整个列表。

使用foreach和使用IndexOf查找所有索引之间的性能差异不大;无论哪种方式,都必须检查列表中的每个元素是否与搜索字符串相等。因此,我的观点是,如果您需要所有索引,请不要费心使用IndexOf。 - KeithS
与 foreach 相比,Linq 的答案遍历 2N+X 个项目,其中 X 是匹配数量。首先它会转换每个元素,然后检查每个元素是否相等,最后再次转换过滤的元素。而 foreach 只在列表中一次从头到尾地遍历。因此,在最好的情况下,Linq 的性能只有 foreach 的一半,最坏的情况下则只有 foreach 的三分之一。 - KeithS
不,linq查询也只会遍历列表一次。 - Magnus
Linq查询将在N个元素上执行2N+X次操作。每个方法都会遍历其整个源可枚举对象,因此从技术上讲,原始列表只被遍历一次,但第二个和第三个方法的源(派生自原始列表并在第二个方法的情况下与原始列表的基数相等)也将被枚举。Foreach更快;它仅遍历源可枚举对象一次,对每个项执行一次相等性检查。不要相信我,使用Stopwatch类进行测试。 - KeithS
不,你的观点是错误的,它只会迭代一次项目(与for循环相同),编译查询可能需要一些时间,所以它可能会稍微慢一些。 - Magnus
源是一个内存列表,因此将使用Linq的IEnumerable部分。没有Queryable提供程序、表达式树或编译涉及其中。每个方法都创建一个占位符对象,看起来像一个IEnumerable,当评估时,它将简单地迭代其源的每个元素,并产生转换对象(Select)或满足条件的对象(Where)。 - KeithS

1

有点丑但能用:

    var searchInList = new List<string>();

//Populate your list

    string stringToLookUp= "Hello world";
    var foundHelloWorldIndexes = new List<int>();

    for (int i = 0; i < searchInList.Count; i++)
        if (searchInList[i].Equals(stringToLookUp))
            foundHelloWorldIndexes.Add(i);

-1

列表的FindAll方法在这里。列表扩展方法Where在这里

这两个方法几乎可以完全满足您的需求,而且它们非常容易使用。网络上有大量的示例,但如果您需要帮助,请告诉我。


2
-1:FindAll和Where返回实例,而不是索引。 OP想知道原始列表中匹配元素的位置; 这两个函数只会返回一个仅包含匹配项的较短列表。 - KeithS

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