Temukan item di Daftar oleh LINQ?

226

Di sini saya punya contoh sederhana untuk menemukan item dalam daftar string. Biasanya saya gunakan untuk loop atau delegasi anonim untuk melakukannya seperti ini:

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 anonymous delegate
      string foundItem = _list.Find( delegate(string item) {
         found++;
         return string.Equals(search, item);
      });
      */
   }
   return found;
}

LINQ baru bagi saya. Saya ingin tahu apakah saya dapat menggunakan LINQ untuk menemukan item dalam daftar? Bagaimana jika memungkinkan?

David.Chu.ca
sumber
Itu hebat. Namun, itu semua adalah gaya ekspresi lamda. Saya menggunakan daftar sederhana di sini. Daftar ini mungkin kelas dengan beberapa properti dan beberapa digunakan untuk pencarian. Jadi setiap cara LINQ untuk mencari seperti "dari .. di ... di mana ... pilih ..."
David.Chu.ca
Nah, maaf. Sebagian besar metode ini (Pertama, Tunggal, Apa Saja, ...) tidak dapat langsung diterjemahkan ke formulir itu.
R. Martinho Fernandes
Nevermind, sebenarnya Anda dapat menyingkirkan lambdas untuk beberapa kasus ...
R. Martinho Fernandes
Jawaban bagus! Saya hanya ingin merasakan pencarian LINQ dari case enumeration.
David.Chu.ca

Jawaban:

478

Ada beberapa cara (perhatikan ini bukan daftar lengkap).

1) Lajang akan mengembalikan hasil tunggal, tetapi akan mengeluarkan pengecualian jika tidak menemukan atau lebih dari satu (yang mungkin atau mungkin tidak seperti yang Anda inginkan):

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

Note SingleOrDefault()akan berperilaku sama, kecuali akan mengembalikan nol untuk tipe referensi, atau nilai default untuk tipe nilai, alih-alih melemparkan pengecualian.

2) Di mana akan mengembalikan semua item yang sesuai dengan kriteria Anda, sehingga Anda dapat memperoleh jumlah IEn dengan satu elemen:

IEnumerable<string> results = myList.Where(s => s == search);

3) Pertama akan mengembalikan item pertama yang cocok dengan kriteria Anda:

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

Note FirstOrDefault()akan berperilaku sama, kecuali akan mengembalikan nol untuk tipe referensi, atau nilai default untuk tipe nilai, alih-alih melemparkan pengecualian.

Rex M
sumber
35
Jawaban yang bagus Saya menemukan SingleOrDefault sebagai jawaban pilihan saya - sama dengan Single tetapi mengembalikan 'null' jika tidak dapat menemukannya.
Eddie Parker
2
Saya tidak tahu Single () atau SingleOrDefault (). Sangat berguna.
draconis
Apakah metode ini dapat digunakan dengan koleksi lain juga suka ReadOnlyCollectionatau ObservableCollection?
yellavon
@yellavon ini adalah metode ekstensi pada semua jenis yang mengimplementasikan IEnumerable<T>atauIQueryable<T>
Rex M
4
Satu hal yang perlu diperhatikan tentang menggunakan SingleOrDefault adalah karena ia mengeluarkan pengecualian jika lebih dari satu kecocokan ada dalam daftar, ia harus mengulangi setiap item, di mana FirstOrDefault akan berhenti mencari setelah kecocokan pertama ditemukan. msdn.microsoft.com/en-us/library/bb342451(v=vs.110).aspx
DavidWainwright
73

Jika Anda ingin indeks elemen, ini akan melakukannya:

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();

Anda tidak dapat menyingkirkan lambda di pass pertama.

Perhatikan bahwa ini akan melempar jika item tidak ada. Ini menyelesaikan masalah dengan beralih ke int nullable:

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();

Jika Anda menginginkan 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();

Jika Anda ingin menghitung jumlah item yang cocok:

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

Jika Anda ingin semua item yang cocok:

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

Dan jangan lupa untuk memeriksa daftar untuk nullsemua kasus ini.

Atau gunakan (list ?? Enumerable.Empty<string>())sebagai ganti list.

Terima kasih kepada Pavel untuk membantu dalam komentar.

R. Martinho Fernandes
sumber
2
Dua poin. Pertama, tidak ada kebutuhan nyata untuk digunakan di string.Equalssini - tidak ada yang salah dengan itu ==. Kedua, saya juga menyebutkan FirstOrDefault(untuk kasus-kasus di mana item mungkin tidak ada di sana), dan Selectdengan indeks untuk mencakup kasus di mana indeks item diperlukan (seperti yang ada dalam sampel dalam pertanyaan itu sendiri).
Pavel Minaev
Saya belum bahagia. Tidak ada indeks -1 (tidak ditemukan) dalam contoh saya. Ada saran?
R. Martinho Fernandes
Selain memeriksa keberadaannya dengan if, first.
R. Martinho Fernandes
Apakah saya perlu memeriksa apakah daftar itu nol dulu?
David.Chu.ca
Pilih melempar ArgumentNullExceptionjika sumbernya nol
R. Martinho Fernandes
13

Jika benar-benar List<string>Anda tidak membutuhkan LINQ, cukup gunakan:

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

Jika Anda mencari item itu sendiri, coba:

string GetItem(string search)
{
    return _list == null ? null : _list.FirstOrDefault(s => s.Equals(search));
}
AgileJon
sumber
1
Mengikuti logika dari contoh pertama, kita dapat menggunakan _list.Find(search)untuk yang kedua.
jwg
12

Apakah Anda ingin item dalam daftar atau item yang sebenarnya itu sendiri (akan menganggap item itu sendiri).

Berikut adalah banyak opsi untuk Anda:

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
sumber
Whoa ... beberapa orang super cepat satu pemicunya;)
Kelsey
bagaimana dengan indeks sebagai nilai pengembalian?
David.Chu.ca
dan apakah saya perlu memeriksa apakah _list adalah nol dalam bentuk dari .. di _list ...?
David.Chu.ca
6

Metode ini lebih mudah dan aman

var lOrders = new List<string>();

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

RckLN
sumber
1
Saya pikir kita bahkan tidak perlu di true : falsebawah ini harus bekerja sama bool insertOrderNew = lOrders.Find(r => r == "1234") == null;
Vbp
5

Bagaimana dengan IndexOf?

Mencari objek yang ditentukan dan mengembalikan indeks kemunculan pertama dalam daftar

Sebagai contoh

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

Perhatikan bahwa ia mengembalikan -1 jika nilainya tidak muncul dalam daftar

> boys.IndexOf("Hermione")  
-1
Kolonel Panic
sumber
2

Saya dulu menggunakan Kamus yang merupakan semacam daftar yang diindeks yang akan memberi saya apa yang saya inginkan ketika saya menginginkannya.

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

Setiap kali saya ingin mengakses nilai margin saya, misalnya, saya menjawab kamus saya:

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

Jadi, tergantung pada apa yang Anda lakukan, kamus bisa bermanfaat.

Will Marcouiller
sumber
Jawaban yang bagus untuk pertanyaan yang berbeda.
jwg
2

Berikut adalah salah satu cara untuk menulis ulang metode Anda untuk menggunakan 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;
}

Jadi, menyebutnya dengan

GetItemIndex("two")akan kembali 1,

dan

GetItemIndex("notthere")akan kembali -1.

Referensi: linqsamples.com

brinch
sumber
1

Coba kode ini:

return context.EntitytableName.AsEnumerable().Find(p => p.LoginID.Equals(loginID) && p.Password.Equals(password)).Select(p => new ModelTableName{ FirstName = p.FirstName, UserID = p.UserID });
Nayeem Mansoori
sumber
1

Jika kita perlu menemukan elemen dari daftar, maka kita dapat menggunakan metode Finddan FindAllekstensi, tetapi ada sedikit perbedaan di antara mereka. Berikut ini sebuah contoh.

 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); 
Sheo Dayal Singh
sumber
1

Ini akan membantu Anda mendapatkan nilai pertama atau standar dalam pencarian Daftar Linq Anda

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

Pencarian ini akan menemukan nilai pertama atau standar yang akan dikembalikan.

befree2j
sumber
0

Anda ingin mencari objek di daftar objek.

Ini akan membantu Anda mendapatkan nilai pertama atau standar dalam pencarian Daftar Linq Anda.

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

atau

var item = (from items in list
    where items.Reference == ent.BackToBackExternalReferenceId
    select items).FirstOrDefault();
Huseyin Durmus
sumber
0

Anda bisa menggunakan FirstOfDefault dengan ekstensi Where Linq untuk mendapatkan kelas MessageAction dari IEnumerable. Reme

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

dimana

Daftar Tindakan {get; set; }

Singa Emas
sumber