Projeksiyon işlemleri (C#)
Projeksiyon, bir nesneyi genellikle yalnızca daha sonra kullanılan özelliklerden oluşan yeni bir forma dönüştürme işlemini ifade eder. Projeksiyonu kullanarak, her nesneden oluşturulan yeni bir tür oluşturabilirsiniz. Bir özelliği yansıtabilir ve üzerinde matematiksel bir işlev gerçekleştirebilirsiniz. Özgün nesneyi değiştirmeden de yansıtabilirsiniz.
Önemli
Bu örnekler bir System.Collections.Generic.IEnumerable<T> veri kaynağı kullanır. Veri kaynaklarını ve ifade ağaçlarını System.Linq.IQueryProviderkullanan System.Linq.IQueryable<T> veri kaynakları. İfade ağaçlarının izin verilen C# söz diziminde sınırlamaları vardır. Ayrıca EF Core gibi her IQueryProvider
veri kaynağı daha fazla kısıtlama uygulayabilir. Veri kaynağınızın belgelerine bakın.
Projeksiyon gerçekleştiren standart sorgu işleci yöntemleri aşağıdaki bölümde listelenmiştir.
Yöntemler
Yöntem adları | Açıklama | C# sorgu ifadesi söz dizimi | Daha Fazla Bilgi |
---|---|---|---|
Seç | Bir dönüştürme işlevini temel alan değerleri projeler. | select |
Enumerable.Select Queryable.Select |
Selectmany | Bir dönüştürme işlevini temel alan değer dizilerini projeler ve sonra bunları tek bir sırayla düzleştirir. | Birden çok from yan tümce kullanma |
Enumerable.SelectMany Queryable.SelectMany |
Posta Kodu | Belirtilen 2-3 diziden öğeler içeren bir demet dizisi oluşturur. | Uygulanamaz. | Enumerable.Zip Queryable.Zip |
Select
Aşağıdaki örnek, dize listesindeki her dizeden ilk harfi yansıtmak için yan tümcesini kullanır select
.
List<string> words = ["an", "apple", "a", "day"];
var query = from word in words
select word.Substring(0, 1);
foreach (string s in query)
{
Console.WriteLine(s);
}
/* This code produces the following output:
a
a
a
d
*/
Yöntem söz dizimini kullanan eşdeğer sorgu aşağıdaki kodda gösterilir:
List<string> words = ["an", "apple", "a", "day"];
var query = words.Select(word => word.Substring(0, 1));
foreach (string s in query)
{
Console.WriteLine(s);
}
/* This code produces the following output:
a
a
a
d
*/
SelectMany
Aşağıdaki örnek, her dizedeki her sözcüğü bir dize listesinde yansıtmak için birden çok from
yan tümce kullanır.
List<string> phrases = ["an apple a day", "the quick brown fox"];
var query = from phrase in phrases
from word in phrase.Split(' ')
select word;
foreach (string s in query)
{
Console.WriteLine(s);
}
/* This code produces the following output:
an
apple
a
day
the
quick
brown
fox
*/
Yöntem söz dizimini kullanan eşdeğer sorgu aşağıdaki kodda gösterilir:
List<string> phrases = ["an apple a day", "the quick brown fox"];
var query = phrases.SelectMany(phrases => phrases.Split(' '));
foreach (string s in query)
{
Console.WriteLine(s);
}
/* This code produces the following output:
an
apple
a
day
the
quick
brown
fox
*/
yöntemi, SelectMany
ilk sıradaki her öğeyi ikinci sıradaki her öğeyle eşleştirmenin birleşimini de oluşturabilir:
var query = from number in numbers
from letter in letters
select (number, letter);
foreach (var item in query)
{
Console.WriteLine(item);
}
Yöntem söz dizimini kullanan eşdeğer sorgu aşağıdaki kodda gösterilir:
var method = numbers
.SelectMany(number => letters,
(number, letter) => (number, letter));
foreach (var item in method)
{
Console.WriteLine(item);
}
Zip
Projeksiyon işleci için Zip
çeşitli aşırı yüklemeler vardır. Zip
Tüm yöntemler, iki veya daha fazla muhtemelen heterojen türün dizileri üzerinde çalışır. İlk iki aşırı yükleme, verilen dizilerden karşılık gelen konumsal türle birlikte tanımlama demetleri döndürür.
Aşağıdaki koleksiyonları göz önünde bulundurun:
// An int array with 7 elements.
IEnumerable<int> numbers = [1, 2, 3, 4, 5, 6, 7];
// A char array with 6 elements.
IEnumerable<char> letters = ['A', 'B', 'C', 'D', 'E', 'F'];
Bu dizileri birlikte yansıtmak için şu işlecini Enumerable.Zip<TFirst,TSecond>(IEnumerable<TFirst>, IEnumerable<TSecond>) kullanın:
foreach ((int number, char letter) in numbers.Zip(letters))
{
Console.WriteLine($"Number: {number} zipped with letter: '{letter}'");
}
// This code produces the following output:
// Number: 1 zipped with letter: 'A'
// Number: 2 zipped with letter: 'B'
// Number: 3 zipped with letter: 'C'
// Number: 4 zipped with letter: 'D'
// Number: 5 zipped with letter: 'E'
// Number: 6 zipped with letter: 'F'
Önemli
Zip işleminden elde edilen sıra hiçbir zaman en kısa diziden uzun olmaz. numbers
ve letters
koleksiyonlarının uzunluğu farklıdır ve sonuçta elde edilen dizi, sıkıştırması gerekmeyen numbers
son öğeyi koleksiyondan atlar.
İkinci aşırı yükleme bir third
dizi kabul eder. Şimdi başka bir koleksiyon oluşturalım:emoji
// A string array with 8 elements.
IEnumerable<string> emoji = [ "🤓", "🔥", "🎉", "👀", "⭐", "💜", "✔", "💯"];
Bu dizileri birlikte yansıtmak için şu işlecini Enumerable.Zip<TFirst,TSecond,TThird>(IEnumerable<TFirst>, IEnumerable<TSecond>, IEnumerable<TThird>) kullanın:
foreach ((int number, char letter, string em) in numbers.Zip(letters, emoji))
{
Console.WriteLine(
$"Number: {number} is zipped with letter: '{letter}' and emoji: {em}");
}
// This code produces the following output:
// Number: 1 is zipped with letter: 'A' and emoji: 🤓
// Number: 2 is zipped with letter: 'B' and emoji: 🔥
// Number: 3 is zipped with letter: 'C' and emoji: 🎉
// Number: 4 is zipped with letter: 'D' and emoji: 👀
// Number: 5 is zipped with letter: 'E' and emoji: ⭐
// Number: 6 is zipped with letter: 'F' and emoji: 💜
Önceki aşırı yükleme gibi yöntemi Zip
de bir tanımlama grubu oluşturur, ancak bu kez üç öğeyle.
Üçüncü aşırı yükleme, sonuç seçici işlevi gören bir Func<TFirst, TSecond, TResult>
bağımsız değişkeni kabul eder. Sıkıştırılmış dizilerden yeni bir sonuç dizisi yansıtabilirsiniz.
foreach (string result in
numbers.Zip(letters, (number, letter) => $"{number} = {letter} ({(int)letter})"))
{
Console.WriteLine(result);
}
// This code produces the following output:
// 1 = A (65)
// 2 = B (66)
// 3 = C (67)
// 4 = D (68)
// 5 = E (69)
// 6 = F (70)
Yukarıdaki Zip
aşırı yüklemeyle, belirtilen işlev ilgili öğelere numbers
ve uygulanır ve letter
sonuçların bir dizisini string
oluşturur.
Select
ile SelectMany
hem hem SelectMany
de Select
öğesinin çalışması, kaynak değerlerden bir sonuç değeri (veya değerler) üretmektir. Select
her kaynak değer için bir sonuç değeri üretir. Bu nedenle genel sonuç, kaynak koleksiyonla aynı sayıda öğeye sahip bir koleksiyondur. Buna karşılık, SelectMany
her kaynak değerden birleştirilmiş altcollections içeren tek bir genel sonuç üretir. bağımsız değişken SelectMany
olarak geçirilen transform işlevinin her kaynak değer için numaralandırılabilir bir değer dizisi döndürmesi gerekir. SelectMany
bu numaralandırılabilir dizileri birleştirerek büyük bir dizi oluşturur.
Aşağıdaki iki çizimde, bu iki yöntemin eylemleri arasındaki kavramsal fark gösterilmektedir. Her durumda selector (transform) işlevinin her kaynak değerden çiçek dizisini seçtiğini varsayalım.
Bu çizimde, kaynak koleksiyonla aynı sayıda öğeye sahip bir koleksiyonun nasıl Select
döndürüldüğü gösterilmektedir.
Bu çizimde, dizilerin ara dizisinin her ara dizideki her değeri içeren son bir sonuç değeriyle nasıl SelectMany
birleştirildiği gösterilmektedir.
Kod örneği
Aşağıdaki örnek ve SelectMany
davranışını Select
karşılaştırır. Kod, kaynak koleksiyondaki her çiçek adı listesinden öğeleri alarak bir "buket" çiçek oluşturur. Aşağıdaki örnekte, dönüştürme işlevinin Select<TSource,TResult>(IEnumerable<TSource>, Func<TSource,TResult>) kullandığı "tek değer" bir değer koleksiyonudur. Bu örnek, her alt sorgudaki her dizeyi listelemek için ek foreach
döngü gerektirir.
class Bouquet
{
public required List<string> Flowers { get; init; }
}
static void SelectVsSelectMany()
{
List<Bouquet> bouquets =
[
new Bouquet { Flowers = ["sunflower", "daisy", "daffodil", "larkspur"] },
new Bouquet { Flowers = ["tulip", "rose", "orchid"] },
new Bouquet { Flowers = ["gladiolis", "lily", "snapdragon", "aster", "protea"] },
new Bouquet { Flowers = ["larkspur", "lilac", "iris", "dahlia"] }
];
IEnumerable<List<string>> query1 = bouquets.Select(bq => bq.Flowers);
IEnumerable<string> query2 = bouquets.SelectMany(bq => bq.Flowers);
Console.WriteLine("Results by using Select():");
// Note the extra foreach loop here.
foreach (IEnumerable<string> collection in query1)
{
foreach (string item in collection)
{
Console.WriteLine(item);
}
}
Console.WriteLine("\nResults by using SelectMany():");
foreach (string item in query2)
{
Console.WriteLine(item);
}
}