Reputation: 14878
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));
Upvotes: 317
Views: 693834
Reputation: 14535
Making use of the Index
extension method, we can have:
public static class EnumerableExtensions
{
public static int IndexOf<T>(this IEnumerable<T> values, Predicate<T> selector)
{
return values.Index().Where(x => selector(x.Item)).Select(x => x.Index).SingleOrDefault(-1);
}
}
Upvotes: 0
Reputation: 103
And IndexOf can be used directly with the object without an explicit comparison.
List<YourObject> listObj = new List<YourObject>();
var obj = new YourObject();
int idx = listObj.IndexOf(obj);
Upvotes: 1
Reputation:
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"));
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 */);
Upvotes: 16
Reputation: 10381
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.
Upvotes: 146
Reputation: 17600
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.
Upvotes: 18
Reputation: 1673
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;
}
}
Upvotes: 0
Reputation: 32561
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
Upvotes: 612
Reputation: 138
If anyone wonders for the Array
version, it goes like this:
int i = Array.FindIndex(yourArray, x => x == itemYouWant);
Upvotes: 6
Reputation: 10792
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.
Upvotes: 3
Reputation: 1500595
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.
Upvotes: 96