How can I get the index of an item in a list in a single step?

C#LinqLookup

C# Problem Overview


How can I find the index of an item in a list without looping through it?

Currently this doesn't look very nice - searching through the list for the same item twice, just to get the index:

var oProp = something;

int theThingIActuallyAmInterestedIn = myList.IndexOf(myList.Single(i => i.Prop == oProp));

C# Solutions


Solution 1 - C#

How about the List.FindIndex Method:

int index = myList.FindIndex(a => a.Prop == oProp);

> This method performs a linear search; therefore, this method is an > O(n) operation, where n is Count.

If the item is not found, it will return -1

Solution 2 - C#

For simple types you can use "IndexOf":

List<string> arr = new List<string>();
arr.Add("aaa");
arr.Add("bbb");
arr.Add("ccc");
int i = arr.IndexOf("bbb"); // Returns 1.

Solution 3 - C#

EDIT: If you're only using a List<> and you only need the index, then List.FindIndex is indeed the best approach. I'll leave this answer here for those who need anything different (e.g. on top of any IEnumerable<>).

Use the overload of Select which takes an index in the predicate, so you transform your list into an (index, value) pair:

var pair = myList.Select((Value, Index) => new { Value, Index })
                 .Single(p => p.Value.Prop == oProp);

Then:

Console.WriteLine("Index:{0}; Value: {1}", pair.Index, pair.Value);

Or if you only want the index and you're using this in multiple places, you could easily write your own extension method which was like Where, but instead of returning the original items, it returned the indexes of those items which matched the predicate.

Solution 4 - C#

If you don't want to use LINQ, then:

int index;
for (int i = 0; i < myList.Count; i++)
{
    if (myList[i].Prop == oProp)
    {
       index = i;
       break;
    }
}

This way you are iterating the list only once.

Solution 5 - C#

  1. A simple solution to find the index for any string value in the List.

    Here is code for a list of strings:

     int indexOfValue = myList.FindIndex(a => a.Contains("insert value from list"));
    
  2. A simple solution to find the index for any integer value in the List.

    Here is code for a list of integers:

     int indexOfNumber = myList.IndexOf(/* insert number from list */);
    

Solution 6 - C#

If anyone wonders for the Array version, it goes like this:

int i = Array.FindIndex(yourArray, x => x == itemYouWant);

Solution 7 - C#

Here's a copy/paste-able extension method for IEnumerable

public static class EnumerableExtensions
{
    /// <summary>
    /// Searches for an element that matches the conditions defined by the specified predicate,
    /// and returns the zero-based index of the first occurrence within the entire <see cref="IEnumerable{T}"/>.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <param name="predicate">The predicate.</param>
    /// <returns>
    /// The zero-based index of the first occurrence of an element that matches the conditions defined by <paramref name="predicate"/>, if found; otherwise it'll throw.
    /// </returns>
    public static int FindIndex<T>(this IEnumerable<T> list, Func<T, bool> predicate)
    {
        var idx = list.Select((value, index) => new {value, index}).Where(x => predicate(x.value)).Select(x => x.index).First();
        return idx;
    }
}

Enjoy.

Solution 8 - C#

That's all fine and good -- but what if you want to select an existing element as the default? In my issue there is no "--select a value--" option.

Here's my code -- you could make it into a one liner if you didn't want to check for no results I suppose...

private void LoadCombo(ComboBox cb, string itemType, string defVal = "")
{
    cb.DisplayMember = "Name";
    cb.ValueMember = "ItemCode";
    cb.DataSource = db.Items.Where(q => q.ItemTypeId == itemType).ToList();

    if (!string.IsNullOrEmpty(defVal))
    {
        var i = ((List<GCC_Pricing.Models.Item>)cb.DataSource).FindIndex(q => q.ItemCode == defVal);
        if (i>=0) cb.SelectedIndex = i;
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDaniel RobinsonView Question on Stackoverflow
Solution 1 - C#Alex FilipoviciView Answer on Stackoverflow
Solution 2 - C#Jose Manuel Abarca RodríguezView Answer on Stackoverflow
Solution 3 - C#Jon SkeetView Answer on Stackoverflow
Solution 4 - C#gzaxxView Answer on Stackoverflow
Solution 5 - C#user5245248View Answer on Stackoverflow
Solution 6 - C#Ali BordbarView Answer on Stackoverflow
Solution 7 - C#SnæbjørnView Answer on Stackoverflow
Solution 8 - C#D. KermottView Answer on Stackoverflow