5

I am looking for a way to get the index of all elements in a list from a keyword search within the list. So for example my list has:

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

Now from this list of strings, i want to get all the indices of elements that say Hello World. I have tried the following but it only returns the first index it finds that has my search criteria:

    for (int i = 0; i< searchInList.Count; i++)
        foundHelloWorld[i] = searchInList.IndexOf("Hello World");

Anyone know of a way to do this?

Thanks

Suman Banerjee
  • 1,923
  • 4
  • 24
  • 40
Ryan
  • 209
  • 3
  • 4
  • 7
  • Are you looking for a list of all indices that contain a duplicate, no matter what the content is? What is the bigger picture? – Chris Trombley Jun 28 '11 at 16:28
  • lol its not hmwk. I have a list that may or may not contain duplicate entries. i want a way to make sure w.e. method i use takes into account the possibility of a duplicate when giving me all the indices – Ryan Jun 28 '11 at 16:33
  • So you only want to know if the list contains duplicates of the specified string, you don't really care about the indices? – Magnus Jun 28 '11 at 16:40

4 Answers4

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

If you're trying to search for more than just "Hello World", you could do

searchInList.Select((value, index) => new {value, index})
    .Where(a => stringsToSearchFor.Any(s => string.Equals(a.value, s)))
    .Select(a => a.index)
Yuriy Faktorovich
  • 67,283
  • 14
  • 105
  • 142
  • it would be interesting if you does it for homework and his teacher allows linq :) –  Jun 28 '11 at 16:28
  • @Andreas he'll get the credit, but really it will mostly hurt him if he's cheating. – Yuriy Faktorovich Jun 28 '11 at 16:29
  • @Yuriy sorry for editing, just wanted to improve the edit-suggestion ... if you do not like it, pleace feel free to revert! –  Jun 28 '11 at 16:32
  • i get an error that says cannot implicitly convert to int – Ryan Jun 28 '11 at 16:45
  • @Ryan I've just tried it and it works. Can you please post the code that doesn't work? – Yuriy Faktorovich Jun 28 '11 at 16:48
  • its basically exactly what you have. i just declared the list above your code like this: List searchInList= new List(); – Ryan Jun 28 '11 at 16:51
  • wait i actually assigned your statement to foundHelloWorld = – Ryan Jun 28 '11 at 16:52
  • @Ryan I thought searchInList would be the list of strings you're trying to search in. To get the results of this to a list, you could do `List results = [my answer].ToList()`. – Yuriy Faktorovich Jun 28 '11 at 16:53
  • Hello world isnt actually the only term for which i need index. I have a list of terms i need to search within searchInLIst and get all the indices in an integer list of all the returned index of search terms – Ryan Jun 28 '11 at 16:56
  • @Magnus actually nothing ... `string.Equals()` is just null-safe and has an overload for `System.StringComparison` ... –  Jun 28 '11 at 19:18
  • Great answer. Well played LAD. – MoonKnight Apr 23 '13 at 09:20
2

Since you know you're looking for ALL occurrences and therefore you must traverse the entire list anyway, you'll gain a lot of readability over using IndexOf by simply examining each element yourself:

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

   i++;
}

You can also use an overload of the Linq Select method that incorporate's the element's index in the source collection; this should be highly readable (and thus maintainable) to Linq-experienced programmers:

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

The above code takes the list and transforms the string into a simple anonymous type incorporating each item's place in the original list. Then, it filters down to only matching elements, and then it projects out the Index (which didn't change through the filtering) into a new List object. However, all this transformation will make this solution perform slower, because this statement will traverse the entire list multiple times.

KeithS
  • 70,210
  • 21
  • 112
  • 164
  • There isn't much performance difference between a foreach and using IndexOf to find all indexes; One way or the other, every element in the list must be examined for equality with the search string. So, my point is don't bother with IndexOf if you need all indexes. – KeithS Jun 28 '11 at 16:44
  • Comparing foreach to the Linq answer, the Linq answer traverses through 2N+X items where X is the number of matches. First it transforms every element, then it examines every element for equality, THEN it transforms the filtered elements again. The foreach only goes through the list once, start-to-finish. So, Linq will perform best-case half as fast and worst-case a third as fast as the foreach. – KeithS Jun 28 '11 at 16:48
  • No, the linq query will also only traverse the list once. – Magnus Jun 28 '11 at 16:53
  • The Linq query will perform 2N+X operations on N elements. Each method will iterate through its entire source enumerable, so technically the original list is traversed once, but the sources of the second and third, derived from and in the case of the second method equal in cardinality to the original list, will also be enumerated. Foreach is faster; it traverses only the source enumerable, only once, performing one equality check per item. Don't believe me, test em with a Stopwatch class. – KeithS Jun 28 '11 at 16:57
  • No your wrong on that, it'll only iterate the the items once (same as in the for loop) compiling the query might take some minor time, so it'll probably be a little slower. – Magnus Jun 28 '11 at 17:04
  • The source is an in-memory list, so the IEnumerable side of Linq will be used. There's no Queryable providers, expression trees or compilation involved. Each method creates a placeholder object that looks like an IEnumerable, that when evaluated will simply iterate through each element of its source and yield return either transformed objects (Select) or objects that meet a condition (Where). – KeithS Jun 28 '11 at 17:10
1

A little ugly but will work:

    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);
Arthur P
  • 1,050
  • 9
  • 16
-1

The FindAll method for lists is here. The list extension method Where is here.

Both of these will do pretty much exactly what you want and they are pretty easy to use. There are abundant examples of each on the internet but if you need help using them just let me know.

Alec
  • 1,646
  • 3
  • 19
  • 35
  • 2
    -1: FindAll and Where return instances, not indexes. The OP wants to know the position of matching elements in the original list; both of these will simply return a shorter list containing only matches. – KeithS Jun 28 '11 at 16:34