LINQ में Group


1061

मान लें कि हमारे पास एक वर्ग है जैसे:

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

अब मेरे पास इस वर्ग की एक सूची है: List<Person> persons;

अब इस सूची में एक ही उदाहरण के साथ कई उदाहरण हो सकते हैं PersonID:

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

क्या कोई ऐसा तरीका है जिससे मैं समूह बना सकता हूं PersonIDऔर उसके पास सभी कारों की सूची प्राप्त कर सकता हूं ?

उदाहरण के लिए, अपेक्षित परिणाम होगा

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

इसलिए समूह बनाने के बाद, मुझे मिलेगा:

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

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

मैंने अब तक जो किया है, उससे:

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

क्या कोई मुझे सही दिशा में इंगित कर सकता है?


1
इसमें एक और उदाहरण भी शामिल है Countऔर Sumयहां stackoverflow.com/questions/3414080/…
डेवलपर

@ मर्टिन कल्मन: मैं क्रिस वॉल्श से सहमत हूं। सबसे अधिक संभावना है कि ओपी के "व्यक्ति (एस)" ​​क्लास (टेबल) वाले ऐप में पहले से ही एक "'सामान्य' '" व्यक्ति (एस) "क्लास (टेबल) होता है जिसमें यूयू होता है। गुण / कॉलम (नाम, लिंग, DOB)। ओपी का "व्यक्ति (कर्मचारी)" वर्ग (तालिका) "सामान्य" "व्यक्ति" "वर्ग" (तालिका) (अर्थात "आदेश-पत्र) (वर्ग) (तालिका) का मुख्य रूप से एक बाल वर्ग (तालिका) होगा। ) बनाम "ऑर्डर (एस)" ​​क्लास (टेबल))। ओपी संभवत: वास्तविक नाम का उपयोग नहीं कर रहा था यदि वह उसी स्कोप में था, जो उसके "सामान्य" "व्यक्ति" वर्ग (टेबल) और / या इस पद के लिए इसे सरल बना सकता है।
टॉम

जवाबों:


1731

बिल्कुल - आप मूल रूप से चाहते हैं:

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

या एक गैर-क्वेरी अभिव्यक्ति के रूप में:

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

मूल रूप से समूह की सामग्री (जब एक के रूप में देखी जाती है IEnumerable<T>) p.carदिए गए कुंजी के लिए मौजूद प्रक्षेपण ( इस मामले में) में जो भी मूल्य थे, का एक क्रम है ।

कैसे GroupByकाम करता है, इस बारे में अधिक जानने के लिए , विषय पर मेरा एडुलिनक पोस्ट देखें ।

(मैंने .NET नामकरण परंपराओं का पालन करने के लिए उपरोक्त नाम दिया PersonIDहै ।)PersonId

वैकल्पिक रूप से, आप एक का उपयोग कर सकते हैं Lookup:

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

फिर आप प्रत्येक व्यक्ति के लिए बहुत आसानी से कार प्राप्त कर सकते हैं:

// This will be an empty sequence for any personId not in the lookup
var carsForPerson = carsByPersonId[personId];

11
@ जोंन स्कीट क्या होगा अगर मैं नाम की तरह एक और संपत्ति जोड़ना चाहता
हूं

22
@ मोहम्मद: फिर आप इसे गुमनाम प्रकार में शामिल करते हैं।
जॉन स्कीट

7
@ user123456 यहाँ समूह की एक अच्छी व्याख्या है, इसमें एक समग्र कुंजी द्वारा समूहीकरण का एक उदाहरण भी शामिल है: कैसे करें: समूह क्वेरी परिणाम (C # प्रोग्रामिंग गाइड)
मैथ्यू डाइपमैन

14
@ मोहम्मद आप कुछ ऐसा कर सकते हैं .GroupBy(p => new {p.Id, p.Name}, p => p, (key, g) => new { PersonId = key.Id, PersonName = key.Name, PersonCount = g.Count()})और आपको वह सभी लोग मिलेंगे जो प्रत्येक व्यक्ति के लिए एक आईडी, नाम, और कई घटनाओं के साथ होते हैं।
क्रिस

11
@ नाम: मैं जानबूझकर .NET नामकरण परंपराओं का पालन कर रहा था, ओपी के नामों को ठीक करते हुए, मूल रूप से। उत्तर में स्पष्ट कर देगा।
जॉन स्कीट

52
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()/**/}


32

आप यह भी आज़मा सकते हैं:

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

यह गलत है कि उसी सूची में समूह नहीं है
विकास गुप्ता

यह काम है, मुझे लगता है कि कुछ याद आ रही है यही कारण है कि यह आपके कोड में काम नहीं करता है।
शुवो सरकार

28

प्रयत्न

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

या

यह जांचने के लिए कि कोई व्यक्ति आपकी सूची में दोहरा रहा है या नहीं

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

13

मैंने क्वेरी सिंटैक्स और मेथड सिंटेक्स के साथ एक वर्किंग कोड सैंपल बनाया है। मुझे आशा है कि यह दूसरों की मदद करता है :)

आप यहां पर .Net फिडेल कोड भी चला सकते हैं:

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

यहाँ परिणाम है:

1
फेरारी
बीएमडब्ल्यू
2
ऑडी
-----------
1
फेरारी
बीएमडब्ल्यू
2
ऑडी


कृपया, यह बताएं कि आपका कोड खातिर क्या करता है। यह सिर्फ एक कोड जवाब है जो लगभग एक गलत जवाब है।
V.7

2

इसे इस्तेमाल करे :

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

लेकिन प्रदर्शन-वार निम्नलिखित अभ्यास बेहतर है और स्मृति उपयोग में अधिक अनुकूलित है (जब हमारे सरणी में लाखों की तरह अधिक आइटम शामिल हैं)

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

4
g.Key.PersonId? g.SelectMany?? आपने स्पष्ट रूप से यह कोशिश नहीं की।
गर्ट अर्नाल्ड

आप लिख रहे हैं मैंने इसमें कुछ कोड कोड संपादित किए और इसका परीक्षण नहीं किया। मेरा मुख्य बिंदु दूसरा भाग था। लेकिन वैसे भी आपके विचार के लिए धन्यवाद। जब मुझे लगा कि यह गलत है तो उस कोड को संपादित करने में बहुत देर हो चुकी है। इसलिए g.Key ने g.Key.PersonId को बदल दिया, और SelectMany के बजाय Select करें! इतना गन्दा सॉरी :)))
akazemis

2
@akazemis: मैं वास्तव में (ओपी के डोमेन के बराबर शब्दों का उपयोग करने के लिए) बनाने की कोशिश कर रहा था SortedDictionary <PersonIdInt, SortedDictionary <CarNameString, CarInfoClass>>। निकटतम मैं LINQ का उपयोग कर सकता है IEnumerable <IGrouping <PersonIdInt, Dictionary <CarNameString, PersonIdCarNameXrefClass>>>। मैंने आपकी forलूप विधि का उपयोग करके समाप्त किया, जो कि btw, 2x तेज था। इसके अलावा, मैं उपयोग करेगा: ए) foreachबनाम forऔर बी) TryGetValueबनाम ContainsKey(डीआरवाई सिद्धांत के लिए दोनों - कोड और रनटाइम में)।
टॉम

1

ऐसा करने का एक वैकल्पिक तरीका अलग हो सकता है PersonIdऔर समूह के साथ जुड़ सकते हैं persons:

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

या धाराप्रवाह एपीआई सिंटैक्स के साथ ही:

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 पहली सूची ( PersonIdहमारे मामले की सूची) में प्रविष्टियों की एक सूची बनाता है , प्रत्येक दूसरी सूची में शामिल प्रविष्टियों के समूह के साथ (सूची persons)।


1

निम्न उदाहरण GroupBy पद्धति का उपयोग उन वस्तुओं को वापस करने के लिए करता है जो कि समूहीकृत हैं PersonID

var results = persons.GroupBy(x => x.PersonID)
              .Select(x => (PersonID: x.Key, Cars: x.Select(p => p.car).ToList())
              ).ToList();

या

 var results = persons.GroupBy(
               person => person.PersonID,
               (key, groupPerson) => (PersonID: key, Cars: groupPerson.Select(x => x.car).ToList()));

या

 var results = from person in persons
               group person by person.PersonID into groupPerson
               select (PersonID: groupPerson.Key, Cars: groupPerson.Select(x => x.car).ToList());

या आप उपयोग कर सकते हैं ToLookup, मूल रूप से ToLookupउपयोग करता है। EqualityComparer<TKey>चाबियाँ की तुलना करने के लिए .Default और समूह द्वारा और शब्दकोश का उपयोग करते समय आपको मैन्युअल रूप से क्या करना चाहिए। मुझे लगता है कि यह बहाना है

 ILookup<int, string> results = persons.ToLookup(
            person => person.PersonID,
            person => person.car);

-1

सबसे पहले, अपना मुख्य क्षेत्र निर्धारित करें। फिर अपने अन्य क्षेत्रों को शामिल करें:

var results = 
    persons
    .GroupBy(n => n.PersonId)
    .Select(r => new Result {PersonID = r.Key, Cars = r.ToList() })
    .ToList()

गैर-टिप्पणी वाला उत्तर / कोड वह तरीका नहीं है कि कैसे स्टैकऑवरफ्लो काम करता है ...
V.7
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.