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?


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


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

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

...


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 .


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.


19

Saya mengerti SelectManybekerja seperti pintasan bergabung.

Jadi kamu bisa:

var orders = customers
             .Where(c => c.CustomerName == "Acme")
             .SelectMany(c => c.Orders);

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.


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

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.


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'

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)

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.


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

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

-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" }

-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.


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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.