Menu

C# LINQ: Where, Select, OrderBy, GroupBy ve Fazlası

LINQ, C#'taki her koleksiyona sorgu operatörleri ekler. Metot sözdizimini ve sorgu sözdizimini, Where ile filtrelemeyi, Select ile projeksiyonu, OrderBy ve ThenBy ile sıralamayı, GroupBy ile gruplamayı, First ile FirstOrDefault tuzağını, toplama işlemlerini ve ertelenmiş yürütmenin sorgunuzun ne zaman çalıştığını nasıl değiştirdiğini öğrenin.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

LINQ (Language Integrated Query), dizileri filtrelemek, dönüştürmek, sıralamak, gruplamak ve özetlemek için bir metot kütüphanesidir. using System.Linq; ekleyin; her dizi, List<T>, Dictionary ve diğer IEnumerable<T>, her biri tek bir elemanla ne yapılacağını söyleyen bir lambda alan Where, Select ve OrderBy gibi metotlar kazanır.

İlk sorgu: metot sözdizimi ve sorgu sözdizimi

LINQ'in iki gösterimi vardır. Metot sözdizimi çağrıları zincirler; sorgu sözdizimi SQL gibi okunur. Derleyici sorgu sözdizimini aynı metot çağrılarına çevirir, bu yüzden aynı sonuçları üretirler.

Çıktı:

95, 91, 88
95, 91, 88

Modern kodda metot sözdizimi daha yaygındır ve bazı operatörler (Take, Distinct, Count, First, ToList) yalnızca metot olarak vardır. Sorgu sözdizimi join'lerde ve let ile ara değişkenler tanıtan sorgularda parlar. Bu sayfanın geri kalanı metot sözdizimini kullanır ve bir şey kattığı yerde sorgu sözdizimini gösterir.

Where ve Select: filtrelemek ve projeksiyon

Where bir koşulu karşılayan elemanları tutar. Select her elemanı başka bir şeye dönüştürür. Birlikte günlük sorguların çoğunu karşılarlar.

Çıktı:

Mug, Kettle
MUG $8.50 | LAMP $32.00 | KETTLE $27.00 | RUG $120.00
Lamp: 38.40
Rug: 144.00
1. Mug 2. Lamp 3. Kettle 4. Rug

Where elemanları asla değiştirmez, Select de kaç tane olduklarını asla değiştirmez. new { p.Name, WithTax = ... } anonim bir tip oluşturur: derleyicinin sizin için yazdığı, property'lerini normal nokta sözdizimiyle okuduğunuz bir sınıf. Yazabileceğiniz bir adı yoktur, bu yüzden birini tutan bir değişken var ile bildirilmelidir ve tek bir metodun içinde kalan sonuçlara uyar.

OrderBy, ThenBy ve birkaç anahtara göre sıralama

Çıktı:

Ana 60
Ana 15
Ben 90
Ben 40
Chloe 25
Ben, Ana, Ben, Chloe, Ana

OrderBy kararlıdır: anahtarları eşit olan elemanlar orijinal sıralarında kalır. İkinci bir anahtar için ThenBy ya da ThenByDescending kullanın. İkinci bir OrderBy her şeyi kendi anahtarına göre yeniden sıralar ve ilk anahtarı yalnızca eşitlik bozucu olarak bırakır: ters öncelik. Sorgu sözdiziminde anahtarlar virgülle ayrılır: orderby o.Customer, o.Total descending.

List<T>.Sort'un aksine OrderBy kaynağa dokunmaz ve yeni bir dizi döndürür.

First, Single, Last ve OrDefault sürümleri

Bunlar bir dizi yerine tek bir eleman döndürür. Düz sürümler döndürecek bir şey olmadığında istisna fırlatır; OrDefault sürümleri tipin varsayılan değerini döndürür.

Çıktı:

Ana
Ben
Bea
True
First: InvalidOperationException
Single: InvalidOperationException
0

Boş bir dizide First'ten gelen istisna, "Sequence contains no elements" (ya da bir koşul hiçbir şeyle eşleşmediğinde "Sequence contains no matching element") mesajlı InvalidOperationException'dır; en çok aranan C# hatalarından biridir. "Hiç yok" normal bir sonuçsa FirstOrDefault kullanın ve null için kontrol edin.

Son satır değer tipi tuzağını gösterir: bir int dizisi için FirstOrDefault hiçbir şey eşleşmediğinde 0 döndürür ve bu gerçek bir 0'dan ayırt edilemez. Where ile filtreleyip önce Any() kontrol edin ya da .NET 6 ve sonrasında kendi varsayılanınızı verin: scores.FirstOrDefault(s => s > 100, -1).

Single "tam olarak bir" içindir: hiç yoksa ya da birden fazlaysa istisna fırlatır; bu da onu bir sorgu kadar bir doğrulama yapar.

Any, All, Count ve Contains

Çıktı:

True
True
True
3
True
True

Any() ilk eşleşmede durur, bu yüzden "bir şey var mı?" diye sormanın doğru yolu items.Any()'dir. Kaynak bir liste ya da dizi gibi bir koleksiyonsa items.Count() > 0 Count property'sini okur, ama bir sorguda ya da başka tembel bir dizide önce her elemanı dolaşır. Boş bir dizide All true döndürür, çünkü koşulu sağlamayan bir eleman yoktur.

Sum, Average, Min ve Max

Çıktı:

Total: 28.25
Items: 7
Priciest: 7.25
Average price: 4.92
0
Average: InvalidOperationException

Boş bir dizinin Sum'ı 0'dır, ama boş bir sayı dizisinin Average, Min ve Max'i InvalidOperationException fırlatır: mantıklı bir cevap yoktur. Any() ile koruyun ya da önce DefaultIfEmpty() kullanın: empty.DefaultIfEmpty(0).Average().

Distinct, Take ve Skip

Çıktı:

home, shop, cart
Page 1: 1 2 3 4 5 6 7 8 9 10
Page 2: 11 12 13 14 15 16 17 18 19 20
Page 3: 21 22 23
12, 15

Distinct her değerin ilk geçişini sırayla tutar. Skip(n).Take(m) standart sayfalama kalıbıdır ve TakeWhile/SkipWhile bir koşulu sağlamayan ilk elemanda durur ya da başlar. Enumerable.Range(start, count) dizi olmadan bir tamsayı dizisi üretir.

GroupBy

GroupBy elemanları bir anahtara göre kovalara ayırır. Her grubun bir Key'i vardır ve kendisi bir dizidir, bu yüzden onu toplayabilirsiniz.

Çıktı:

North: 3 sales, total 600
South: 2 sales, total 400
East: 1 sales, total 350
Top rep: Ana 400
North -> Ana/Chloe/Ana; South -> Ben/Eli; East -> Dev

Gruplar sıralı değil, anahtarlarının kaynakta ilk göründüğü sırayla çıkar (North, South, East); bunu istiyorsanız OrderBy(g => g.Key) ekleyin. Sorgu sözdiziminde group X by K her gruba neyin gireceğini seçer (burada yalnızca temsilcinin adı) ve into g sorgunun devam edebilmesi için gruba ad verir.

ToList, ToArray ve ToDictionary

To... metotları sorguyu çalıştırır ve sonuçları saklar.

Çıktı:

ben@x.com
2
ToDictionary: ArgumentException

İki eleman aynı anahtarı ürettiğinde ToDictionary, tıpkı Dictionary.Add gibi ArgumentException fırlatır. Tekrarlar bekleniyorsa önce gruplayın (wordCounts'un yaptığı gibi) ya da her anahtarı bir değerler dizisine eşleyen ToLookup'ı kullanın.

Ertelenmiş yürütme

Where, Select, OrderBy, GroupBy ve diğer operatörlerin çoğu bir sorgu nesnesi döndürür ve bir şey onu dolaşana kadar hiçbir iş yapmaz. Bunun görmeye değer iki sonucu vardır:

Çıktı:

25, 40, 99
  converting 10
  converting 25
  converting 40
  converting 99
Count: 4
  converting 10
  converting 25
  converting 40
  converting 99
Max: 9900
  converting 10
  converting 25
  converting 40
  converting 99
Cached: 4, 9900

İlk sorgu, sorgu yazıldıktan sonra eklendiği halde 99'u gördü: filtre string.Join onu dolaştığında çalıştı. İkinci sorgu dönüşümlerini iki kez yazdırdı, çünkü Count() ve Max() onu her biri sıfırdan dolaştı. Ucuz bir lambda ile bu yalnızca boşa harcanan iştir; lambda'nın içinde bir veritabanı sorgusu, bir dosya okuma ya da rastgele bir sayı olduğunda iki geçiş farklı veri döndürebilir. Bir sonucu birden fazla kez kullanacaksanız onu ToList() ya da ToArray() ile somutlaştırın.

Tek bir değer döndüren operatörler (Count, Sum, First, Any, Max) ve To... metotları hemen çalışır. Bu tembelliğin nasıl kurulduğu için IEnumerable ve yield sayfasına bakın.

Hızlı başvuru

OperatörYaptığıDöndürdüğü
Where(x => cond)FiltrelerDizi (ertelenmiş)
Select(x => expr)Her birini dönüştürürDizi (ertelenmiş)
SelectMany(x => seq)İç içe dizileri düzleştirirDizi (ertelenmiş)
OrderBy, ThenBy (+Descending)Sıralar, kararlıDizi (ertelenmiş)
GroupBy(x => key)Anahtara göre kovalarGruplardan oluşan dizi (ertelenmiş)
Distinct, Take, SkipTekrarları atar, sayfalarDizi (ertelenmiş)
First, Single, LastTek eleman, yoksa istisnaEleman
FirstOrDefault vb.Tek eleman ya da varsayılanEleman
Any, All, ContainsTest ederbool
Count, Sum, Min, Max, AverageToplarSayı
ToList, ToArray, ToDictionaryÇalıştırır ve saklarKoleksiyon

Yaygın hatalar

  • Boş olabilecek bir dizide First(). "Sequence contains no elements" fırlatır; FirstOrDefault kullanın ve kontrol edin.
  • İki OrderBy çağrısı. İkinci anahtar asıl anahtar olur; ThenBy kullanın.
  • Bir sorguyu birkaç kez dolaşmak. İş tekrarlanır; bir kez ToList() çağırın.
  • Bir sorgunun kaynağının anlık görüntüsünü almasını beklemek. Kaynağı yazıldığında değil, dolaşıldığında okur.
  • Boş bir dizide Average, Min, Max. İstisna fırlatırlar; Any() ya da DefaultIfEmpty ile koruyun.
  • Eleman olup olmadığını test etmek için Count() > 0. Any() ilkinde durur.

Sıkça Sorulan Sorular

C#'ta LINQ nedir?

LINQ (Language Integrated Query), System.Linq içinde Where, Select, OrderBy ve GroupBy gibi, herhangi bir IEnumerable<T> üzerinde çalışan bir extension metot kümesidir: diziler, listeler, dictionary'ler ve diğer sorguların sonuçları. C#'ta derleyicinin aynı metot çağrılarına çevirdiği bir sorgu sözdizimi de (from x in items where ... select ...) vardır.

LINQ'te Select ile Where arasındaki fark nedir?

Where filtreler: lambda'nın true döndürdüğü elemanları tutar ve onları değiştirmez. Select projeksiyon yapar: her elemanı bir property ya da yeni bir nesne gibi başka bir şeye dönüştürür ve sayıyı aynı tutar. Sık sık zincirlenirler: people.Where(p => p.Age >= 18).Select(p => p.Name).

First ile FirstOrDefault arasındaki fark nedir?

First() ilk elemanı (ya da bir koşul için ilk eşleşmeyi) döndürür ve hiç yoksa InvalidOperationException ("Sequence contains no elements" ya da "no matching element") fırlatır. FirstOrDefault() bunun yerine tipin varsayılan değerini döndürür: sınıflar için null, int için 0; bu yüzden sonucu kullanmadan önce kontrol edin.

LINQ ile iki alana göre nasıl sıralanır?

OrderBy'dan sonra ThenBy zincirleyin: orders.OrderBy(o => o.Customer).ThenByDescending(o => o.Total). OrderBy'ı iki kez çağırmak çalışmaz: ikinci çağrı tüm diziyi yeniden sıralar, bu yüzden onun anahtarı birincil olur ve ilk anahtar yalnızca eşitlikleri bozar; kastedilenin tersi.

LINQ'te GroupBy nasıl çalışır?

GroupBy(x => key) her farklı anahtar için bir grup döndürür. Her grup bir IGrouping<TKey, TElement>'tir: bir Key property'si vardır ve kendisi o anahtara sahip elemanlardan oluşan bir dizidir, bu yüzden üzerinde Count(), Sum() ya da Select çağırabilirsiniz. Gruplar anahtarlarının ilk göründüğü sırayla çıkar.

LINQ'te ertelenmiş yürütme nedir?

Çoğu LINQ operatörü çağırdığınızda çalışmaz; her dolaşıldığında (foreach, ToList(), Count() vb. ile) çalışan bir sorgu döndürür. Bu yüzden bir sorgu, tanımlandıktan sonra kaynağa yapılan değişiklikleri görür ve onu iki kez dolaşmak işi iki kez yapar. Bir kez çalıştırıp sonuçları tutmak için ToList() ya da ToArray() çağırın.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA