LINQ හි ​​කණ්ඩායම් කරන්න


1078

අපට මෙවැනි පංතියක් තිබේ යැයි සිතමු:

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

මට මෙම පන්තියේ ලැයිස්තුවක් ඇත: List<Person> persons;

මෙම ලැයිස්තුවට එකම PersonIDs සමඟ බහුවිධ අවස්ථා තිබිය හැක , උදාහරණයක් ලෙස:

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ඔහු සතුව ඇති සියලුම මෝටර් රථ ලැයිස්තුව ලබා ගත හැකි ක්‍රමයක් තිබේද?

උදාහරණයක් ලෙස, අපේක්ෂිත ප්‍රති result ලය වනු ඇත

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/...
සංවර්ධක

Ar මාටින් කෝල්මන්: මම ක්‍රිස් වොල්ෂ් සමඟ එකඟ වෙමි. බොහෝ දුරට OP හි "පුද්ගලයා (ය)" පන්තිය (වගුව) ඇති යෙදුමකට දැනටමත් "" සාමාන්‍ය "" "පුද්ගල (ය)" පංතිය (වගුව) ඇති අතර එය usu ඇත. ගුණාංග / තීරු (එනම් නම, ස්ත්‍රී පුරුෂ භාවය, DOB). OP හි "පුද්ගලයා (ය)" පන්තිය (වගුව) "සාමාන්‍ය" "" පුද්ගල (ය) "පන්තියේ (වගුව) (එනම්" ඇණවුම් අයිතම (ය) "පන්තියේ (වගුව) ළමා පන්තියක් (වගුව) වනු ඇත. ) එදිරිව. "ඇණවුම (ය)" පන්තිය (වගුව)). ඔහුගේ සාමාන්‍ය සාමාන්‍ය විෂය පථයට සමාන නම්, ඔහු භාවිතා කරන සැබෑ නම OP භාවිතා නොකරනු ඇත. "(පුද්ගලයා)" පන්තිය (වගුව) සහ / හෝ මෙම තනතුර සඳහා එය සරල කර ඇත.
ටොම්

Answers:


1761

නියත වශයෙන්ම - ඔබට මූලික වශයෙන් අවශ්‍ය වන්නේ:

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
name ජෝන් ස්කීට් මට නම වැනි වෙනත් දේපලක් එක් කිරීමට අවශ්‍ය නම්
user123456

22
O මොහමඩ්: එවිට ඔබ එය නිර්නාමික වර්ගයට ඇතුළත් කරන්න.
ජෝන් ස්කීට්

7
12 user123456 සමූහය පිළිබඳ හොඳ පැහැදිලි කිරීමක් මෙහි ඇත, එයට සංයුක්ත යතුරකින් කණ්ඩායම් කිරීම පිළිබඳ උදාහරණයක් ද ඇතුළත් වේ: කෙසේද: කණ්ඩායම් විමසුම්
ප්‍රති Results ල

14
Oh මොහමඩ් ඔබට එවැනි දෙයක් කළ හැකි අතර හැඳුනුම්පතක් .GroupBy(p => new {p.Id, p.Name}, p => p, (key, g) => new { PersonId = key.Id, PersonName = key.Name, PersonCount = g.Count()}), නමක් සහ එක් එක් පුද්ගලයාට සිදුවීම් ගණනාවක් සමඟ සිදුවන සියලු පුද්ගලයින් ඔබට ලැබෙනු ඇත.
ක්‍රිස්

11
amekame: මම හිතාමතාම .NET නම් කිරීමේ සම්මුතීන් අනුගමනය කරමින්, OP හි නම් නිවැරදි කරමින්, මූලික වශයෙන්. පිළිතුරෙන් එය පැහැදිලි කරයි.
ජෝන් ස්කීට්

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


33

ඔබට මෙය උත්සාහ කළ හැකිය:

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

එකම ලැයිස්තුව කාණ්ඩගත නොකිරීම වැරදියි
විකාස් ගුප්තා

එය වැඩකි, මම සිතන්නේ යමක් අස්ථානගත වී ඇති බැවින් එය ඔබේ කේතයේ ක්‍රියා නොකරන්නේ එබැවිනි.
ෂුවෝ සර්කර්

29

උත්සාහ කරන්න

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

හෝ

ඔබගේ ලැයිස්තුවේ කිසියම් පුද්ගලයෙක් පුනරාවර්තනය වන්නේ දැයි පරීක්ෂා කිරීමට උත්සාහ කරන්න

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

13

විමසුම් සින්ටැක්ස් සහ ක්‍රම සින්ටැක්ස් සමඟ වැඩකරන කේත නියැදියක් මම නිර්මාණය කර ඇත්තෙමි. එය අනෙක් අයට උපකාරී වේ යැයි මම බලාපොරොත්තු වෙමි :)

ඔබට .Net Fiddle හි කේතය ක්‍රියාත්මක කළ හැකිය:

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

ප්රති result ලය මෙන්න:

1
ෆෙරාරි
BMW
2
අවී
-----------
1
ෆෙරාරි
BMW
2
අවී


කරුණාකර, ඔබගේ කේතය වෙනුවෙන් කරන්නේ කුමක්ද යන්න පැහැදිලි කරන්න. මෙය කේත පිළිතුරක් වන අතර එය වැරදි පිළිතුරකි.
F8ER

3

මේක උත්සාහ කරන්න :

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 වෙනුවට තෝරන්න! ඉතින්
අවුල් සහගතයි

2
azakazemis: මම ඇත්ත වශයෙන්ම නිර්මාණය කිරීමට උත්සාහ කළෙමි (OP හි වසමට සමාන යෙදුම් භාවිතා කිරීමට) SortedDictionary <PersonIdInt, SortedDictionary <CarNameString, CarInfoClass>>. මට ලින්ක් භාවිතා කළ හැකි ආසන්නම දේ විය 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(),
    };

හෝ චතුර කථික API සින්ටැක්ස් සමඟ සමාන වේ:

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>යතුරු සංසන්දනය කිරීමට සහ කණ්ඩායම් අනුව සහ ශබ්ද කෝෂයට භාවිතා කරන විට ඔබ අතින් කළ යුතු දේ කරන්න. මම හිතන්නේ එය අනුමත කිරීමක් නොවේ

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

0

පළමුව, ඔබේ යතුරු ක්ෂේත්‍රය සකසන්න. ඉන්පසු ඔබේ වෙනත් ක්ෂේත්‍ර ඇතුළත් කරන්න:

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

අදහස් නොදක්වන පිළිතුර / කේතය StackOverflow ක්‍රියා කරන ආකාරය නොවේ ...
F8ER
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.