Vetítési műveletek (C#)

A kivetítés egy objektum új formává alakításának műveletére utal, amely gyakran csak azokból a tulajdonságokból áll, amelyeket később használnak. A kivetítés használatával létrehozhat egy új típust, amely az egyes objektumokból épül fel. Kivetíthet egy tulajdonságot, és matematikai függvényt is végrehajthat rajta. Az eredeti objektumot módosítás nélkül is kivetítheti.

A vetítést végző szabványos lekérdezési operátor-metódusok a következő szakaszban találhatók.

Metódusok

Metódusnevek Leírás C# lekérdezési kifejezés szintaxisa További információ
Kijelölés Transzformációs függvényen alapuló projektek értékei. select Enumerable.Select
Queryable.Select
SelectMany Transzformációs függvényen alapuló értéksorozatokat projektel, majd egy sorozatba simítja őket. Több from záradék használata Enumerable.SelectMany
Queryable.SelectMany
Irányítószám 2–3 megadott sorozat elemeit tartalmazó üstöksorozatot hoz létre. Nem alkalmazható. Enumerable.Zip
Queryable.Zip

Select

Az alábbi példa a select záradék használatával veti ki az egyes sztringek első betűit a sztringek listájában.

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
*/

A metódusszintaxissal egyenértékű lekérdezés a következő kódban jelenik meg:

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

Az alábbi példa több from záradékot használ a sztringek listájában szereplő egyes sztringek minden egyes szójának kivetítéséhez.

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
*/

A metódusszintaxissal egyenértékű lekérdezés a következő kódban jelenik meg:

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
*/

A SelectMany metódus az első sorozat minden elemének és a második sorozat minden elemének összeillesztésének kombinációját is alkothatja:

var query = from number in numbers
            from letter in letters
            select (number, letter);

foreach (var item in query)
{
    Console.WriteLine(item);
}

A metódusszintaxissal egyenértékű lekérdezés a következő kódban jelenik meg:

var method = numbers
    .SelectMany(number => letters,
    (number, letter) => (number, letter));

foreach (var item in method)
{
    Console.WriteLine(item);
}

Zip

A vetítési operátornak Zip számos túlterhelése van. Zip Az összes metódus két vagy több, esetleg heterogén típusú sorozaton dolgozik. Az első két túlterhelés a megfelelő pozíciótípussal tér vissza a megadott szekvenciákból.

Vegye figyelembe a következő gyűjteményeket:

// 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'];

A sorozatok együtt történő kivetítéséhez használja az operátort Enumerable.Zip<TFirst,TSecond>(IEnumerable<TFirst>, IEnumerable<TSecond>) :

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'

Fontos

A zip műveletből származó sorozat soha nem hosszabb a legrövidebb sorozatnál. A numbers gyűjtemények hossza eltér letters , és az eredményül kapott sorozat kihagyja az utolsó elemet a numbers gyűjteményből, mivel nincs semmi, amellyel zip-et kell húzni.

A második túlterhelés egy sorozatot third fogad el. Hozzunk létre egy másik gyűjteményt, nevezetesen emoji:

// A string array with 8 elements.
IEnumerable<string> emoji = [ "🤓", "🔥", "🎉", "👀", "⭐", "💜", "✔", "💯"];

A sorozatok együtt történő kivetítéséhez használja az operátort Enumerable.Zip<TFirst,TSecond,TThird>(IEnumerable<TFirst>, IEnumerable<TSecond>, IEnumerable<TThird>) :

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: 💜

Az előző túlterheléshez hasonlóan a Zip metódus egy rekordot is kivetít, de ezúttal három elemet használ.

A harmadik túlterhelés olyan argumentumot Func<TFirst, TSecond, TResult> fogad el, amely eredményválasztóként működik. A tömörített szekvenciákból új eredményül kapott sorozatot is kivetíthet.

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)

Az előző Zip túlterhelés esetén a megadott függvény a megfelelő elemekre numbers lesz alkalmazva, és letteraz string eredmények sorozatát eredményezi.

Select Szemben SelectMany

Mindkettő Select feladata, hogy SelectMany eredményértéket (vagy értékeket) állít elő a forrásértékekből. Select minden forrásértékhez egy eredményértéket állít elő. Az összesített eredmény tehát egy olyan gyűjtemény, amelynek ugyanannyi eleme van, mint a forrásgyűjteménynek. Ezzel szemben egyetlen összesített eredményt hoz létre, SelectMany amely az egyes forrásértékekből származó összefűzött részösszetevőket tartalmazza. Az argumentumként átadott átalakítási függvénynek SelectMany az egyes forrásértékek számbavételes értéksorát kell visszaadnia. SelectMany összefűzi ezeket az enumerálható sorozatokat egy nagy sorozat létrehozásához.

Az alábbi két ábra a két módszer műveletei közötti fogalmi különbséget mutatja be. Tegyük fel, hogy a választó (átalakító) függvény minden egyes forrásértékből kiválasztja a virágtömböt.

Ez az ábra azt mutatja be, hogyan Select ad vissza egy olyan gyűjteményt, amelynek ugyanannyi eleme van, mint a forrásgyűjteménynek.

A Select() műveletét megjelenítő ábra

Ez az ábra bemutatja, hogyan SelectMany fűzi össze a tömbök köztes sorozatát egy végső eredményértékbe, amely az egyes köztes tömbök minden értékét tartalmazza.

A SelectMany() műveletét bemutató ábra

Mintakód

Az alábbi példa a következők viselkedését hasonlítja SelectSelectManyössze: A kód egy virágcsokrot hoz létre úgy, hogy a forrásgyűjteményben lévő virágnevek minden egyes listájából eltávolítja az elemeket. Az alábbi példában az átalakító függvény Select<TSource,TResult>(IEnumerable<TSource>, Func<TSource,TResult>) által használt "egyetlen érték" értékgyűjtemény. Ehhez a példához szükség van a további foreach hurokra az egyes alhálózatok sztringjeinek számbavételéhez.

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

Lásd még