Perbedaan Antara Select dan SelectMany

1074

Saya telah mencari perbedaan antara Selectdan SelectManytetapi saya belum dapat menemukan jawaban yang cocok. Saya perlu mempelajari perbedaannya ketika menggunakan LINQ To SQL tetapi yang saya temukan hanyalah contoh array standar.

Dapatkah seseorang memberikan contoh LINQ To SQL?

Tarik
sumber
8
Anda dapat melihat kode untuk SelectMany dengan satu fungsi, atau dengan dua fungsi referenceource.microsoft.com/#System.Core/System/Linq/…
barlop
1
Jika Anda terbiasa dengan Kotlin, ia memiliki implementasi yang sangat mirip untuk koleksi seperti peta alias C # Select dan flatMap alias C # SelectMany. Pada dasarnya fungsi ekstensi perpustakaan Kotlin std untuk koleksi memiliki kemiripan dengan perpustakaan C # Linq.
Arsenius

Jawaban:

1622

SelectManymeratakan kueri yang mengembalikan daftar daftar. Sebagai contoh

public class PhoneNumber
{
    public string Number { get; set; }
}

public class Person
{
    public IEnumerable<PhoneNumber> PhoneNumbers { get; set; }
    public string Name { get; set; }
}

IEnumerable<Person> people = new List<Person>();

// Select gets a list of lists of phone numbers
IEnumerable<IEnumerable<PhoneNumber>> phoneLists = people.Select(p => p.PhoneNumbers);

// SelectMany flattens it to just a list of phone numbers.
IEnumerable<PhoneNumber> phoneNumbers = people.SelectMany(p => p.PhoneNumbers);

// And to include data from the parent in the result: 
// pass an expression to the second parameter (resultSelector) in the overload:
var directory = people
   .SelectMany(p => p.PhoneNumbers,
               (parent, child) => new { parent.Name, child.Number });

Demo langsung di .NET Fiddle

Mike Two
sumber
1
Pertanyaan terkait pada nesting SelectMany untuk meratakan struktur hierarki bersarang.
Kacang Merah
1
Untuk memahami hasilPilih lebih lanjut Tautan di bawah ini membantu blogs.interknowlogy.com/2008/10/10/...
jamir
Satu lagi demo dengan hasil dari orang tua: dotnetfiddle.net/flcdCC
Evgeniy Kosjakov
terima kasih atas tautan biola!
Aerin
197

Pilih banyak seperti operasi lintas bergabung dalam SQL di mana dibutuhkan produk silang.
Misalnya kalau sudah

Set A={a,b,c}
Set B={x,y}

Pilih banyak yang dapat digunakan untuk mendapatkan set berikut

{ (x,a) , (x,b) , (x,c) , (y,a) , (y,b) , (y,c) }

Perhatikan bahwa di sini kita mengambil semua kemungkinan kombinasi yang dapat dibuat dari elemen himpunan A dan himpunan B.

Ini adalah contoh LINQ yang bisa Anda coba

List<string> animals = new List<string>() { "cat", "dog", "donkey" };
List<int> number = new List<int>() { 10, 20 };

var mix = number.SelectMany(num => animals, (n, a) => new { n, a });

campuran akan memiliki elemen berikut dalam struktur datar seperti

{(10,cat), (10,dog), (10,donkey), (20,cat), (20,dog), (20,donkey)}
Sriwantha Attanayake
sumber
4
Saya tahu ini sudah tua, tetapi saya ingin mengucapkan terima kasih untuk ini, itu menyelamatkan saya banyak! :) Ini dapat bermanfaat untuk memiliki referensi ke kode-kode itu juga: stackoverflow.com/questions/3479980/… Cheers!
user3439065
4
SelectMany tidak harus digunakan seperti itu. Ini memiliki opsi untuk hanya mengambil satu fungsi juga.
barlop
2
Aku tak tahu apakah itu benar untuk mengatakan bahwa ini adalah bagaimana SelectMany adalah . Sebaliknya, ini adalah cara yang SelectManydapat digunakan, tetapi sebenarnya bukan cara normal untuk menggunakannya.
Dave Cousineau
1
Ini adalah jawaban yang paling sederhana untuk saya mengerti.
Chaim Eliyah
Akan lebih baik jika Anda juga menunjukkan Wherekondisi setelah SelectMany
Nitin Kt
126

masukkan deskripsi gambar di sini

var players = db.SoccerTeams.Where(c => c.Country == "Spain")
                            .SelectMany(c => c.players);

foreach(var player in players)
{
    Console.WriteLine(player.LastName);
}
  1. De Gea
  2. Alba
  3. Costa
  4. Vila
  5. Busquets

...

AlejandroR
sumber
9
contoh data yang bagus
ben_mj
2
dapatkah Anda menambahkan contoh untuk dipilih untuk melengkapi jawaban ini :)
Harry
73

SelectMany()memungkinkan Anda menciutkan urutan multidimensi dengan cara yang sebaliknya akan membutuhkan urutan kedua Select()atau loop.

Lebih detail di posting blog ini .

Michael Petrotta
sumber
Tetapi yang pertama mengembalikan tipe Enumerables of Children, contoh kedua mengembalikan tipe Parents? Sebenarnya saya sedikit bingung, apakah Anda akan membukanya sedikit lagi?
Tarik
Sebaliknya, sebenarnya. Yang kedua akan benar-benar meratakan hierarki enumerables, sehingga Anda mendapatkan Anak kembali. Coba artikel di tautan yang saya tambahkan, lihat apakah itu membantu.
Michael Petrotta
Yang pertama tampaknya tidak legal. Saya pikir poster itu sendiri bingung. Yang kedua akan mengembalikan banyak orang tua.
mqp
Terima kasih, well sebenarnya ya contohnya agak membingungkan :) tapi terima kasih lagi untuk mencoba membantu saya.
Tarik
37

Ada beberapa kelebihan SelectMany. Salah satunya memungkinkan Anda untuk melacak hubungan apa pun antara orang tua dan anak-anak saat melintasi hierarki.

Contoh : misalkan Anda memiliki struktur berikut:League -> Teams -> Player .

Anda dapat dengan mudah mengembalikan koleksi pemain yang datar. Namun Anda dapat kehilangan referensi ke tim yang menjadi bagian dari pemain.

Untungnya ada kelebihan untuk tujuan tersebut:

var teamsAndTheirLeagues = 
         from helper in leagues.SelectMany
               ( l => l.Teams
                 , ( league, team ) => new { league, team } )
                      where helper.team.Players.Count > 2 
                           && helper.league.Teams.Count < 10
                           select new 
                                  { LeagueID = helper.league.ID
                                    , Team = helper.team 
                                   };

Contoh sebelumnya diambil dari blog IK Dan . Saya sangat menyarankan Anda melihatnya.

roland
sumber
19

Saya mengerti SelectManybekerja seperti pintasan bergabung.

Jadi kamu bisa:

var orders = customers
             .Where(c => c.CustomerName == "Acme")
             .SelectMany(c => c.Orders);
Nathan Koop
sumber
Contoh yang diberikan berfungsi, tetapi SelectMany tidak persis berfungsi seperti gabungan. Gabung memungkinkan untuk "menggunakan" bidang apa pun dari tabel asli plus bidang apa pun dari tabel gabungan. Tapi di sini Anda harus menentukan objek daftar yang dilampirkan ke tabel asli. Misalnya .SelectMany(c => new {c.CompanyName, c.Orders.ShippedDate});tidak mau bekerja. SelectMany agak meratakan daftar daftar - dan Anda dapat memilih (tetapi hanya satu per satu) daftar yang ada untuk hasilnya. Sebagai perbandingan: Inner gabung di Linq .
Matt
13

Select adalah proyeksi satu-ke-satu yang sederhana dari elemen sumber ke elemen hasil. Select- Many digunakan ketika ada beberapa klausa dalam ekspresi kueri: setiap elemen dalam urutan asli digunakan untuk menghasilkan urutan baru.

Alexandr
sumber
7

Beberapa SelectMany mungkin tidak diperlukan. Di bawah 2 pertanyaan memberikan hasil yang sama.

Customers.Where(c=>c.Name=="Tom").SelectMany(c=>c.Orders)

Orders.Where(o=>o.Customer.Name=="Tom")

Untuk hubungan 1-ke-Banyak,

  1. jika Mulai dari "1", SelectMany diperlukan, itu akan meratakan banyak.
  2. jika Mulai dari "Banyak", SelectMany tidak diperlukan. ( masih dapat memfilter dari "1" , juga ini lebih sederhana daripada di bawah standar permintaan bergabung)

from o in Orders
join c in Customers on o.CustomerID equals c.ID
where c.Name == "Tom"
select o
Rm558
sumber
4

Tanpa terlalu teknis - basis data dengan banyak Organisasi, masing-masing dengan banyak Pengguna: -

var orgId = "123456789";

var userList1 = db.Organizations
                   .Where(a => a.OrganizationId == orgId)
                   .SelectMany(a => a.Users)
                   .ToList();

var userList2 = db.Users
                   .Where(a => a.OrganizationId == orgId)
                   .ToList();

keduanya mengembalikan daftar ApplicationUser yang sama untuk Organisasi yang dipilih.

"Proyek" pertama dari Organisasi ke Pengguna, yang kedua menanyakan tabel Pengguna secara langsung.

RickL
sumber
3

Lebih jelas ketika kueri mengembalikan string (array char):

Misalnya jika daftar 'Buah' mengandung 'apel'

'Pilih' mengembalikan string:

Fruits.Select(s=>s) 

[0]: "apple"

'SelectMany' meratakan string:

Fruits.SelectMany(s=>s)

[0]: 97  'a'
[1]: 112 'p'
[2]: 112 'p'
[3]: 108 'l'
[4]: 101 'e'
Eric Bole-Feysot
sumber
2

Hanya untuk tampilan alternatif yang dapat membantu beberapa programmer fungsional di luar sana:

  • Select adalah map
  • SelectManyadalah bind(atau flatMapuntuk orang Scala / Kotlin Anda)
Matt Klein
sumber
2

Pertimbangkan contoh ini:

        var array = new string[2]
        {
            "I like what I like",
            "I like what you like"
        };
        //query1 returns two elements sth like this:
        //fisrt element would be array[5]  :[0] = "I" "like" "what" "I" "like"
        //second element would be array[5] :[1] = "I" "like" "what" "you" "like"
        IEnumerable<string[]> query1 = array.Select(s => s.Split(' ')).Distinct();

        //query2 return back flat result sth like this :
        // "I" "like" "what" "you"
        IEnumerable<string> query2 = array.SelectMany(s => s.Split(' ')).Distinct();

Jadi ketika Anda melihat nilai duplikat seperti "I" atau "like" telah dihapus dari query2 karena "SelectMany" meratakan dan memproyeksikan berbagai urutan. Tapi query1 mengembalikan urutan array string. dan karena ada dua array berbeda di query1 (elemen pertama dan kedua), tidak ada yang akan dihapus.

MG Lee
sumber
mungkin lebih baik untuk sekarang menyertakan .Distinct () di akhir dan menyatakan itu menghasilkan "aku" "seperti" "apa" "aku" "suka" "aku" "suka" "seperti apa" "kamu" "suka"
Prof
1

Satu lagi contoh bagaimana SelectMany + Select dapat digunakan untuk mengumpulkan data objek sub array.

Misalkan kita memiliki pengguna dengan telepon mereka:

class Phone { 
    public string BasePart = "555-xxx-xxx"; 
}

class User { 
    public string Name = "Xxxxx";
    public List<Phone> Phones; 
}

Sekarang kita perlu memilih BaseParts semua ponsel dari semua pengguna:

var usersArray = new List<User>(); // array of arrays
List<string> allBaseParts = usersArray.SelectMany(ua => ua.Phones).Select(p => p.BasePart).ToList();
KEMBL
sumber
Menurut Anda mana yang lebih baik? Milik Anda atauusersArray.SelectMany(ua => ua.Phones.Select(p => p.BasePart))
Michael Best
-1

Berikut adalah contoh kode dengan koleksi kecil yang diinisialisasi untuk pengujian:

class Program
{
    static void Main(string[] args)
    {
        List<Order> orders = new List<Order>
        {
            new Order
            {
                OrderID = "orderID1",
                OrderLines = new List<OrderLine>
                {
                    new OrderLine
                    {
                        ProductSKU = "SKU1",
                        Quantity = 1
                    },
                    new OrderLine
                    {
                        ProductSKU = "SKU2",
                        Quantity = 2
                    },
                    new OrderLine
                    {
                        ProductSKU = "SKU3",
                        Quantity = 3
                    }
                }
            },
            new Order
            {
                OrderID = "orderID2",
                OrderLines = new List<OrderLine>
                {
                    new OrderLine
                    {
                        ProductSKU = "SKU4",
                        Quantity = 4
                    },
                    new OrderLine
                    {
                        ProductSKU = "SKU5",
                        Quantity = 5
                    }
                }
            }
        };

        //required result is the list of all SKUs in orders
        List<string> allSKUs = new List<string>();

        //With Select case 2 foreach loops are required
        var flattenedOrdersLinesSelectCase = orders.Select(o => o.OrderLines);
        foreach (var flattenedOrderLine in flattenedOrdersLinesSelectCase)
        {
            foreach (OrderLine orderLine in flattenedOrderLine)
            {
                allSKUs.Add(orderLine.ProductSKU);
            }
        }

        //With SelectMany case only one foreach loop is required
        allSKUs = new List<string>();
        var flattenedOrdersLinesSelectManyCase = orders.SelectMany(o => o.OrderLines);
        foreach (var flattenedOrderLine in flattenedOrdersLinesSelectManyCase)
        {
            allSKUs.Add(flattenedOrderLine.ProductSKU);
        }

       //If the required result is flattened list which has OrderID, ProductSKU and Quantity,
       //SelectMany with selector is very helpful to get the required result
       //and allows avoiding own For loops what according to my experience do code faster when
       // hundreds of thousands of data rows must be operated
        List<OrderLineForReport> ordersLinesForReport = (List<OrderLineForReport>)orders.SelectMany(o => o.OrderLines,
            (o, ol) => new OrderLineForReport
            {
                OrderID = o.OrderID,
                ProductSKU = ol.ProductSKU,
                Quantity = ol.Quantity
            }).ToList();
    }
}
class Order
{
    public string OrderID { get; set; }
    public List<OrderLine> OrderLines { get; set; }
}
class OrderLine
{
    public string ProductSKU { get; set; }
    public int Quantity { get; set; }
}
class OrderLineForReport
{
    public string OrderID { get; set; }
    public string ProductSKU { get; set; }
    public int Quantity { get; set; }
}
Sharunas Bielskis
sumber
-2

The SelectManyMetode mengetuk turun IEnumerable<IEnumerable<T>>menjadi IEnumerable<T>, seperti komunisme, setiap elemen berperilaku dengan cara yang sama (seorang pria bodoh memiliki hak yang sama dari satu genious).

var words = new [] { "a,b,c", "d,e", "f" };
var splitAndCombine = words.SelectMany(x => x.Split(','));
// returns { "a", "b", "c", "d", "e", "f" }
snr
sumber
-5

Itu adalah cara terbaik untuk mengerti menurut saya.

            var query =
            Enumerable
                .Range(1, 10)
                .SelectMany(ints => Enumerable.Range(1, 10), (a, b) => $"{a} * {b} = {a * b}")
                .ToArray();

        Console.WriteLine(string.Join(Environment.NewLine, query));

        Console.Read();

Contoh Tabel Perkalian.

pengguna5966157
sumber
4
Hanya jika makna "terbaik" telah berubah secara dramatis.
Vahid Amiri
2
jadi ini cara terbaik menurutmu ?? lalu apa cara berpikir yang sulit ??
Syed Ali