Unterschied zwischen Select und SelectMany

1073

Ich habe den Unterschied zwischen Selectund gesucht, SelectManyaber ich konnte keine passende Antwort finden. Ich muss den Unterschied bei der Verwendung von LINQ To SQL lernen, aber alles, was ich gefunden habe, sind Standard-Array-Beispiele.

Kann jemand ein LINQ To SQL-Beispiel bereitstellen?

Tarik
quelle
8
Sie können den Code für SelectMany mit einer Funktion oder mit zwei Funktionen referenzieren.
sourceource.microsoft.com/#System.Core/System/Linq/…
1
Wenn Sie mit Kotlin vertraut sind, hat es ziemlich ähnliche Implementierungen für Sammlungen wie map aka C # Select und flatMap aka C # SelectMany. Grundsätzlich haben Kotlin Standard-Bibliothekserweiterungsfunktionen für Sammlungen Ähnlichkeit mit der C # Linq-Bibliothek.
Arsenius

Antworten:

1621

SelectManyglättet Abfragen, die Listen von Listen zurückgeben. Zum Beispiel

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

Live-Demo auf .NET Fiddle

Mike Zwei
quelle
1
Verwandte Frage zum Verschachteln von SelectMany, um eine verschachtelte hierarchische Struktur zu reduzieren.
Die rote Erbse
1
Um resultSelector besser zu verstehen Der folgende Link hilft blogs.interknowlogy.com/2008/10/10/…
jamir
Eine weitere Demo mit Ergebnissen von Eltern: dotnetfiddle.net/flcdCC
Evgeniy Kosjakov
Danke für den Geigenlink!
Aerin
197

Viele auswählen ist wie eine Cross-Join-Operation in SQL, bei der das Cross-Produkt verwendet wird.
Zum Beispiel, wenn wir haben

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

Wählen Sie viele aus, um den folgenden Satz zu erhalten

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

Beachten Sie, dass wir hier alle möglichen Kombinationen nehmen, die aus den Elementen von Satz A und Satz B gemacht werden können.

Hier ist ein LINQ-Beispiel, das Sie ausprobieren können

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

Die Mischung hat folgende Elemente in flacher Struktur wie

{(10,cat), (10,dog), (10,donkey), (20,cat), (20,dog), (20,donkey)}
Sriwantha Attanayake
quelle
4
Ich weiß, das ist alt, aber ich wollte mich dafür bedanken, es hat mich sehr gerettet! :) Es kann nützlich sein, auch auf diese Codes zu verweisen : stackoverflow.com/questions/3479980/… Prost!
user3439065
4
SelectMany muss nicht so verwendet werden. Es besteht die Möglichkeit, auch nur eine Funktion zu übernehmen.
Barlop
2
Ich weiß nicht, ob es richtig ist zu sagen, dass dies so SelectMany ist . Dies ist eher ein Weg, der SelectManyverwendet werden kann, aber eigentlich nicht der normale Weg, ihn zu verwenden.
Dave Cousineau
1
Dies war die einfachste Antwort, die ich verstehen konnte.
Chaim Eliyah
Es wäre gut, wenn Sie auch Wherenach SelectMany
Nitin Kt
126

Geben Sie hier die Bildbeschreibung ein

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. Villa
  5. Busquets

...

AlejandroR
quelle
9
tolle Beispieldaten
ben_mj
2
Harry
73

SelectMany()Mit dieser Option können Sie eine mehrdimensionale Sequenz so reduzieren, dass andernfalls eine Sekunde Select()oder eine Schleife erforderlich wäre .

Weitere Details in diesem Blogbeitrag .

Michael Petrotta
quelle
Aber die erste gibt Enumerables-Kinder zurück, das zweite Beispiel gibt Eltern zurück? Eigentlich bin ich ein bisschen verwirrt, würdest du es ein bisschen mehr öffnen?
Tarik
Eigentlich anders herum. Die zweite Option reduziert die Hierarchie der Aufzählungszeichen vollständig, sodass Sie Kinder zurückerhalten. Probieren Sie den Artikel unter dem von mir hinzugefügten Link aus und prüfen Sie, ob dies hilfreich ist.
Michael Petrotta
Der erste scheint nicht legal zu sein. Ich denke, das Plakat wurde selbst verwirrt. Der zweite würde eine Aufzählung von Eltern zurückgeben.
mqp
Danke, na ja, die Beispiele waren irgendwie verwirrend :) aber nochmals vielen Dank, dass Sie versucht haben, mir zu helfen.
Tarik
37

Es gibt mehrere Überlastungen SelectMany. Mit einer davon können Sie jede Beziehung zwischen Eltern und Kindern verfolgen, während Sie die Hierarchie durchlaufen.

Beispiel : Angenommen, Sie haben die folgende Struktur : League -> Teams -> Player.

Sie können problemlos eine flache Sammlung von Spielern zurückgeben. Sie können jedoch jegliche Bezugnahme auf das Team verlieren, zu dem der Spieler gehört.

Glücklicherweise gibt es eine Überlastung für diesen Zweck:

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

Das vorherige Beispiel stammt aus Dans IK-Blog . Ich empfehle Ihnen dringend, einen Blick darauf zu werfen.

Roland
quelle
19

Ich verstehe SelectMany, wie eine Verknüpfung zu arbeiten.

Also kannst du:

var orders = customers
             .Where(c => c.CustomerName == "Acme")
             .SelectMany(c => c.Orders);
Nathan Koop
quelle
Das bereitgestellte Beispiel funktioniert, aber SelectMany funktioniert nicht genau wie ein Join. Ein Join ermöglicht die "Verwendung" eines beliebigen Feldes der ursprünglichen Tabelle sowie eines beliebigen Feldes der verbundenen Tabelle. Hier müssen Sie jedoch ein Objekt einer Liste angeben, die an die ursprüngliche Tabelle angehängt ist. Zum Beispiel .SelectMany(c => new {c.CompanyName, c.Orders.ShippedDate});würde nicht funktionieren. SelectMany reduziert die Liste der Listen eher - und Sie können eine (jeweils nur eine) der enthaltenen Listen für das Ergebnis auswählen. Zum Vergleich: Inner Join in Linq .
Matt
13

Select ist eine einfache Eins-zu-Eins-Projektion vom Quellelement zum Ergebniselement. Select-Many wird verwendet, wenn ein Abfrageausdruck mehrere from-Klauseln enthält: Jedes Element in der ursprünglichen Sequenz wird zum Generieren einer neuen Sequenz verwendet.

Alexandr
quelle
7

Einige SelectMany sind möglicherweise nicht erforderlich. Unter 2 Abfragen erhalten Sie das gleiche Ergebnis.

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

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

Für 1-zu-viele-Beziehung,

  1. Wenn Start von "1", SelectMany benötigt wird, werden die vielen abgeflacht.
  2. Wenn Sie mit "Viele" beginnen, wird SelectMany nicht benötigt. ( immer noch in der Lage, von "1" zu filtern , auch dies ist einfacher als unter der Standard-Join-Abfrage)

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

Ohne zu technisch zu werden - Datenbank mit vielen Organisationen, jede mit vielen Benutzern: -

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

Beide geben dieselbe ApplicationUser-Liste für die ausgewählte Organisation zurück.

Das erste "Projekte" von Organisation zu Benutzer, das zweite fragt die Benutzertabelle direkt ab.

RickL
quelle
3

Es ist klarer, wenn die Abfrage eine Zeichenfolge (ein Array von Zeichen) zurückgibt:

Zum Beispiel, wenn die Liste 'Früchte' 'Apfel' enthält.

'Select' gibt die Zeichenfolge zurück:

Fruits.Select(s=>s) 

[0]: "apple"

'SelectMany' glättet die Zeichenfolge:

Fruits.SelectMany(s=>s)

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

Nur für eine alternative Ansicht, die einigen funktionalen Programmierern da draußen helfen kann:

  • Select ist map
  • SelectManyist bind(oder flatMapfür Ihre Scala / Kotlin Leute)
Matt Klein
quelle
2

Betrachten Sie dieses Beispiel:

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

Wie Sie sehen, wurden doppelte Werte wie "I" oder "Gefällt mir" aus query2 entfernt, da "SelectMany" mehrere Sequenzen abflacht und projiziert. Aber query1 gibt eine Folge von String-Arrays zurück. und da es in query1 zwei verschiedene Arrays gibt (erstes und zweites Element), wird nichts entfernt.

MG Lee
quelle
wahrscheinlich besser, jetzt .Distinct () am Ende einzuschließen und anzugeben, dass es "Ich" "mag" "was" "Ich" "mag" "Ich" "mag" "was" "du" "magst"
Prof
1

Ein weiteres Beispiel, wie SelectMany + Select verwendet werden kann, um Subarray-Objektdaten zu akkumulieren.

Angenommen, wir haben Benutzer mit ihren Telefonen:

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

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

Jetzt müssen wir die BaseParts aller Telefone aller Benutzer auswählen:

var usersArray = new List<User>(); // array of arrays
List<string> allBaseParts = usersArray.SelectMany(ua => ua.Phones).Select(p => p.BasePart).ToList();
KEMBL
quelle
Was denkst du ist besser? Ihre oderusersArray.SelectMany(ua => ua.Phones.Select(p => p.BasePart))
Michael Best
-1

Hier ist ein Codebeispiel mit einer initialisierten kleinen Sammlung zum Testen:

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
quelle
-2

Die SelectManyMethode schlägt IEnumerable<IEnumerable<T>>ein IEnumerable<T>und wie der Kommunismus verhält sich jedes Element gleich (ein dummer Kerl hat die gleichen Rechte wie ein Genie).

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

Es ist der beste Weg zu verstehen, denke ich.

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

Beispiel für eine Multiplikationstabelle.

user5966157
quelle
4
Nur wenn sich die Bedeutung von "am besten" dramatisch geändert hat.
Vahid Amiri
2
Das ist also der beste Weg, wie du denkst? Was ist dann die schwierige Art zu denken?
Syed Ali