it-swarm.com.de

Gruppieren nach in LINQ

Nehmen wir an, wir haben eine Klasse wie

class Person { 
    internal int PersonID; 
    internal string car  ; 
}

Jetzt habe ich eine Liste dieser Klasse: List<Person> persons;

Diese Liste kann nun mehrere Instanzen mit denselben PersonIDs haben, zum Beispiel:

persons[0] = new Person { PersonID = 1, car = "Ferrari" }; 
persons[1] = new Person { PersonID = 1, car = "BMW"     }; 
persons[2] = new Person { PersonID = 2, car = "Audi"    }; 

Gibt es eine Möglichkeit, mich nach personID zu gruppieren und die Liste aller Autos zu erhalten, die er hat?

Das erwartete Ergebnis wäre beispielsweise

class Result { 
   int PersonID;
   List<string> cars; 
}

Nach der Gruppierung würde ich also Folgendes erhalten:

results[0].PersonID = 1; 
List<string> cars = results[0].cars; 

result[1].PersonID = 2; 
List<string> cars = result[1].cars;

Nach dem, was ich bisher gemacht habe:

var results = from p in persons
              group p by p.PersonID into g
              select new { PersonID = g.Key, // this is where I am not sure what to do

Könnte mich bitte jemand in die richtige Richtung weisen?

971
test123

Absolut - Sie wollen im Grunde:

var results = from p in persons
              group p.car by p.PersonId into g
              select new { PersonId = g.Key, Cars = g.ToList() };

Oder als Nicht-Abfrageausdruck:

var results = persons.GroupBy(
    p => p.PersonId, 
    p => p.car,
    (key, g) => new { PersonId = key, Cars = g.ToList() });

Grundsätzlich ist der Inhalt der Gruppe (bei der Ansicht als IEnumerable<T>) eine Folge von Werten, die in der Projektion (in diesem Fall p.car) für den angegebenen Schlüssel enthalten waren.

Weitere Informationen zur Funktionsweise von GroupBy finden Sie in meinem Edulinq-Beitrag zum Thema .

(Ich habe PersonID in PersonId umbenannt, um . NET-Namenskonventionen .)

Alternativ können Sie auch ein Lookup verwenden:

var carsByPersonId = persons.ToLookup(p => p.PersonId, p => p.car);

Sie können dann ganz einfach die Autos für jede Person bekommen:

// This will be an empty sequence for any personId not in the lookup
var carsForPerson = carsByPersonId[personId];
1621
Jon Skeet
var results = from p in persons
              group p by p.PersonID into g
              select new { PersonID = g.Key,
                           /**/car = g.Select(g=>g.car).FirstOrDefault()/**/}
48
Tallat
var results = from p in persons
              group p by p.PersonID into g
              select new { PersonID = g.Key, Cars = g.Select(m => m.car) };
35

Sie können dies auch versuchen.

var results= persons.GroupBy(n => new { n.PersonId, n.car})
                .Select(g => new {
                               g.Key.PersonId,
                               g.Key.car)}).ToList();
30
shuvo sarker

versuchen

persons.GroupBy(x => x.PersonId).Select(x => x)

oder

um zu überprüfen, ob sich eine Person in Ihrer Liste wiederholt, versuchen Sie es

persons.GroupBy(x => x.PersonId).Where(x => x.Count() > 1).Any(x => x)
25
Code First

Ich habe ein funktionierendes Codebeispiel mit Abfragesyntax und Methodensyntax erstellt. Ich hoffe es hilft den anderen :)

Sie können den Code auch unter .Net Fiddle ausführen:

using System;
using System.Linq;
using System.Collections.Generic;

class Person
{ 
    public int PersonId; 
    public string car  ; 
}

class Result
{ 
   public int PersonId;
   public List<string> Cars; 
}

public class Program
{
    public static void Main()
    {
        List<Person> persons = new List<Person>()
        {
            new Person { PersonId = 1, car = "Ferrari" },
            new Person { PersonId = 1, car = "BMW" },
            new Person { PersonId = 2, car = "Audi"}
        };

        //With Query Syntax

        List<Result> results1 = (
            from p in persons
            group p by p.PersonId into g
            select new Result()
                {
                    PersonId = g.Key, 
                    Cars = g.Select(c => c.car).ToList()
                }
            ).ToList();

        foreach (Result item in results1)
        {
            Console.WriteLine(item.PersonId);
            foreach(string car in item.Cars)
            {
                Console.WriteLine(car);
            }
        }

        Console.WriteLine("-----------");

        //Method Syntax

        List<Result> results2 = persons
            .GroupBy(p => p.PersonId, 
                     (k, c) => new Result()
                             {
                                 PersonId = k,
                                 Cars = c.Select(cs => cs.car).ToList()
                             }
                    ).ToList();

        foreach (Result item in results2)
        {
            Console.WriteLine(item.PersonId);
            foreach(string car in item.Cars)
            {
                Console.WriteLine(car);
            }
        }
    }
}

Hier ist das Ergebnis:

 1 
 Ferrari 
 BMW 
 2 
 Audi 
 ----------- 
 1 
 Ferrari 
 BMW 
 2 
 Audi 
 
13
Recev Yildiz

Versuche dies :

var results= persons.GroupBy(n => n.PersonId)
            .Select(g => new {
                           PersonId=g.Key,
                           Cars=g.Select(p=>p.car).ToList())}).ToList();

In Bezug auf die Leistung ist die folgende Vorgehensweise jedoch besser und in Bezug auf die Speichernutzung optimierter (wenn unser Array viel mehr Elemente wie z. B. Millionen enthält):

var carDic=new Dictionary<int,List<string>>();
for(int i=0;i<persons.length;i++)
{
   var person=persons[i];
   if(carDic.ContainsKey(person.PersonId))
   {
        carDic[person.PersonId].Add(person.car);
   }
   else
   {
        carDic[person.PersonId]=new List<string>(){person.car};
   }
}
//returns the list of cars for PersonId 1
var carList=carDic[1];
2
akazemis

Eine alternative Möglichkeit, dies zu tun, könnte darin bestehen, ein bestimmtes PersonId auszuwählen und einen Gruppenbeitritt mit persons durchzuführen:

var result = 
    from id in persons.Select(x => x.PersonId).Distinct()
    join p2 in persons on id equals p2.PersonId into gr // apply group join here
    select new 
    {
        PersonId = id,
        Cars = gr.Select(x => x.Car).ToList(),
    };

Oder dasselbe mit fließender API-Syntax:

var result = persons.Select(x => x.PersonId).Distinct()
    .GroupJoin(persons, id => id, p => p.PersonId, (id, gr) => new
    {
        PersonId = id,
        Cars = gr.Select(x => x.Car).ToList(),
    });

GroupJoin erzeugt eine Liste von Einträgen in der ersten Liste (in unserem Fall eine Liste von PersonId) mit jeweils einer Gruppe von verbundenen Einträgen in der zweiten Liste (Liste von persons) .

1
Dmitry Stepanov