253

Here I have a simple example to find an item in a list of strings. Normally I use a for loop or anonymous delegate to do it like this:

int GetItemIndex(string search)
{
   int found = -1;
   if ( _list != null )
   {
     foreach (string item in _list) // _list is an instance of List<string>
     {
        found++;
        if ( string.Equals(search, item) )
        {
           break;
        }
      }
      /* Use an anonymous delegate
      string foundItem = _list.Find( delegate(string item) {
         found++;
         return string.Equals(search, item);
      });
      */
   }
   return found;
}

LINQ is new for me. Can I use LINQ to find an item in the list? If it is possible, how?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
David.Chu.ca
  • 37,408
  • 63
  • 148
  • 190

14 Answers14

544

There are a few ways (note that this is not a complete list).

  1. Single will return a single result, but will throw an exception if it finds none or more than one (which may or may not be what you want):

     string search = "lookforme";
     List<string> myList = new List<string>();
     string result = myList.Single(s => s == search);
    

Note that SingleOrDefault() will behave the same, except it will return null for reference types, or the default value for value types, instead of throwing an exception.

  1. Where will return all items which match your criteria, so you may get an IEnumerable<string> with one element:

     IEnumerable<string> results = myList.Where(s => s == search);
    
  2. First will return the first item which matches your criteria:

     string result = myList.First(s => s == search);
    

Note that FirstOrDefault() will behave the same, except it will return null for reference types, or the default value for value types, instead of throwing an exception.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rex M
  • 142,167
  • 33
  • 283
  • 313
  • 42
    Great answer. I found SingleOrDefault to be my answer of choice - same as Single but returns 'null' if it can't find it. – Eddie Parker Mar 07 '13 at 05:46
  • 3
    I didn't know either Single() or SingleOrDefault(). Very useful. – draconis Aug 21 '14 at 11:31
  • Can these methods be used with other collections too like `ReadOnlyCollection` or `ObservableCollection`? – yellavon Nov 21 '14 at 04:11
  • @yellavon these are extension methods on any type that implements `IEnumerable` or `IQueryable` – Rex M Nov 23 '14 at 00:18
  • Old question but still high in Google research, could you add FirstOrDefault() ? – Martin Verjans Sep 07 '17 at 17:41
  • 8
    One thing to note about using SingleOrDefault is that because it throws an exception if more than one match is in the list, it has to iterate through every item, where FirstOrDefault will stop searching once the first match is found. https://msdn.microsoft.com/en-us/library/bb342451(v=vs.110).aspx – DavidWainwright Dec 01 '17 at 14:37
79

If you want the index of the element, this will do it:

int index = list.Select((item, i) => new { Item = item, Index = i })
                .First(x => x.Item == search).Index;

// or
var tagged = list.Select((item, i) => new { Item = item, Index = i });
int index = (from pair in tagged
            where pair.Item == search
            select pair.Index).First();

You can't get rid of the lambda in the first pass.

Note that this will throw if the item doesn't exist. This solves the problem by resorting to nullable ints:

var tagged = list.Select((item, i) => new { Item = item, Index = (int?)i });
int? index = (from pair in tagged
            where pair.Item == search
            select pair.Index).FirstOrDefault();

If you want the item:

// Throws if not found
var item = list.First(item => item == search);
// or
var item = (from item in list
            where item == search
            select item).First();

// Null if not found
var item = list.FirstOrDefault(item => item == search);
// or
var item = (from item in list
            where item == search
            select item).FirstOrDefault();

If you want to count the number of items that match:

int count = list.Count(item => item == search);
// or
int count = (from item in list
            where item == search
            select item).Count();

If you want all the items that match:

var items = list.Where(item => item == search);
// or
var items = from item in list
            where item == search
            select item;

And don't forget to check the list for null in any of these cases.

Or use (list ?? Enumerable.Empty<string>()) instead of list.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
12

If it really is a List<string> you don't need LINQ, just use:

int GetItemIndex(string search)
{
    return _list == null ? -1 : _list.IndexOf(search);
}

If you are looking for the item itself, try:

string GetItem(string search)
{
    return _list == null ? null : _list.FirstOrDefault(s => s.Equals(search));
}
AgileJon
  • 53,070
  • 5
  • 41
  • 38
  • 1
    Following the logic of the first example, we could use `_list.Find(search)` for the second. – jwg Sep 24 '13 at 10:06
12

Do you want the item in the list or the actual item itself (would assume the item itself).

Here are a bunch of options for you:

string result = _list.First(s => s == search);

string result = (from s in _list
                 where s == search
                 select s).Single();

string result = _list.Find(search);

int result = _list.IndexOf(search);
Kelsey
  • 47,246
  • 16
  • 124
  • 162
7

This method is easier and safer

var lOrders = new List<string>();

bool insertOrderNew = lOrders.Find(r => r == "1234") == null ? true : false

RckLN
  • 4,272
  • 4
  • 30
  • 34
  • 2
    I think we don't even need `true : false` below should work same `bool insertOrderNew = lOrders.Find(r => r == "1234") == null;` – Vbp Jan 08 '16 at 02:36
5

How about IndexOf?

Searches for the specified object and returns the index of the first occurrence within the list

For example

> var boys = new List<string>{"Harry", "Ron", "Neville"};  
> boys.IndexOf("Neville")  
2
> boys[2] == "Neville"
True

Note that it returns -1 if the value doesn't occur in the list

> boys.IndexOf("Hermione")  
-1
Colonel Panic
  • 132,665
  • 89
  • 401
  • 465
4

This will help you in getting the first or default value in your LINQ List search

var results = _List.Where(item => item == search).FirstOrDefault();

This search will find the first or default value, which it will return.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
befree2j
  • 361
  • 5
  • 11
2

I used to use a Dictionary which is some sort of an indexed list which will give me exactly what I want when I want it.

Dictionary<string, int> margins = new Dictionary<string, int>();
margins.Add("left", 10);
margins.Add("right", 10);
margins.Add("top", 20);
margins.Add("bottom", 30);

Whenever I wish to access my margins values, for instance, I address my dictionary:

int xStartPos = margins["left"];
int xLimitPos = margins["right"];
int yStartPos = margins["top"];
int yLimitPos = margins["bottom"];

So, depending on what you're doing, a dictionary can be useful.

Will Marcouiller
  • 23,773
  • 22
  • 96
  • 162
2

Here is one way to rewrite your method to use LINQ:

public static int GetItemIndex(string search)
{
    List<string> _list = new List<string>() { "one", "two", "three" };

    var result = _list.Select((Value, Index) => new { Value, Index })
            .SingleOrDefault(l => l.Value == search);

    return result == null ? -1 : result.Index;
}

Thus, calling it with

GetItemIndex("two") will return 1,

and

GetItemIndex("notthere") will return -1.

Reference: linqsamples.com

René Vogt
  • 43,056
  • 14
  • 77
  • 99
brinch
  • 2,544
  • 7
  • 33
  • 55
2

If we need to find an element from the list, then we can use the Find and FindAll extensions method, but there is a slight difference between them. Here is an example.

 List<int> items = new List<int>() { 10, 9, 8, 4, 8, 7, 8 };

  // It will return only one 8 as Find returns only the first occurrence of matched elements.
     var result = items.Find(ls => ls == 8);      
 // this will returns three {8,8,8} as FindAll returns all the matched elements.
      var result1 = items.FindAll(ls => ls == 8); 
Stephen Byrne
  • 7,400
  • 1
  • 31
  • 51
Sheo Dayal Singh
  • 1,591
  • 19
  • 11
1

Try this code:

return context.EntitytableName.AsEnumerable().Find(p => p.LoginID.Equals(loginID) && p.Password.Equals(password)).Select(p => new ModelTableName{ FirstName = p.FirstName, UserID = p.UserID });
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Nayeem Mansoori
  • 821
  • 1
  • 15
  • 41
1

You can use FirstOfDefault with the Where LINQ extension to get a MessageAction class from the IEnumerable. Reme

var action = Message.Actions.Where(e => e.targetByName == className).FirstOrDefault<MessageAction>();

where

List<MessageAction> Actions { get; set; }
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Golden Lion
  • 3,840
  • 2
  • 26
  • 35
1

One more way to check the existence of an element in a List<string>:

var result = myList.Exists(users => users.Equals("Vijai"))
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Vijai
  • 2,369
  • 3
  • 25
  • 32
0

You want to search an object in object list.

This will help you in getting the first or default value in your Linq List search.

var item = list.FirstOrDefault(items =>  items.Reference == ent.BackToBackExternalReferenceId);

or

var item = (from items in list
    where items.Reference == ent.BackToBackExternalReferenceId
    select items).FirstOrDefault();
Huseyin Durmus
  • 380
  • 6
  • 14
  • Part of this is plagiarised from [befree2j's answer](https://stackoverflow.com/questions/1175645/find-an-item-in-a-list-by-linq/32838048#32838048) (see [the previous revision](https://stackoverflow.com/revisions/32838048/2)). – Peter Mortensen Jun 11 '21 at 20:24