c# - LINQ में समूह




group-by (7)

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

आप यहां नेट नेटल पर भी कोड चला सकते हैं:

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
Ferrari
BMW
2
Audi
-----------
1
Ferrari
BMW
2
Audi

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

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

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

अब इस सूची में एक ही व्यक्ति आईडी के साथ कई उदाहरण हो सकते हैं, उदाहरण के लिए:

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 मैं personID द्वारा personID कर सकता 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

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


var results = from p in persons
              group p by p.PersonID into g
              select new { PersonID = g.Key, Cars = g.Select(m => m.car) };

आप यह भी कोशिश कर सकते हैं।

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

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

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

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 कैसे काम करता है, इस बारे में अधिक जानकारी के लिए, विषय पर मेरी एडुलिनक पोस्ट देखें।

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

वैकल्पिक रूप से, आप एक 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];

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

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

पूछताछ:

SELECT purchases.*
FROM purchases
LEFT JOIN purchases as p 
ON 
  p.customer = purchases.customer 
  AND 
  purchases.total < p.total
WHERE p.total IS NULL

वह कैसे काम करता है! (मैं वहाँ गया था)

हम यह सुनिश्चित करना चाहते हैं कि प्रत्येक खरीद के लिए हमारे पास केवल उच्चतम कुल है।

कुछ सैद्धांतिक सामग्री (यदि आप केवल क्वेरी को समझना चाहते हैं तो इस भाग को छोड़ दें)

कुल मिलाकर एक कार्य टी (ग्राहक, आईडी) जहां यह नाम और आईडी दिया गया मान देता है यह साबित करने के लिए कि दिया गया कुल (टी (ग्राहक, आईडी)) उच्चतम है, हमें यह साबित करना होगा कि हम या तो साबित करना चाहते हैं

  • ∀x टी (ग्राहक, आईडी)> टी (ग्राहक, एक्स) (यह कुल उस ग्राहक के लिए अन्य सभी कुल से अधिक है)

या

  • ¬x टी (ग्राहक, आईडी) <टी (ग्राहक, एक्स) (उस ग्राहक के लिए कोई उच्च कुल मौजूद नहीं है)

पहले दृष्टिकोण के लिए हमें उस नाम के लिए सभी रिकॉर्ड प्राप्त करने की आवश्यकता होगी जो मुझे वास्तव में पसंद नहीं है।

दूसरे को यह कहने का एक स्मार्ट तरीका चाहिए कि इस से कोई रिकॉर्ड अधिक नहीं हो सकता है।

एसक्यूएल पर वापस

अगर हम नाम पर तालिका में शामिल हो जाते हैं और कुल मिलाकर तालिका से कम है:

      LEFT JOIN purchases as p 
      ON 
      p.customer = purchases.customer 
      AND 
      purchases.total < p.total

हम यह सुनिश्चित करते हैं कि सभी रिकॉर्ड्स जिनके पास एक ही उपयोगकर्ता के लिए उच्चतम कुल मिलाकर एक और रिकॉर्ड हो,

purchases.id, purchases.customer, purchases.total, p.id, p.customer, p.total
1           , Tom           , 200             , 2   , Tom   , 300
2           , Tom           , 300
3           , Bob           , 400             , 4   , Bob   , 500
4           , Bob           , 500
5           , Alice         , 600             , 6   , Alice   , 700
6           , Alice         , 700

इससे हमें प्रत्येक समूह के लिए उच्चतम कुल फ़िल्टर करने में मदद मिलेगी, जिसमें कोई समूह आवश्यक नहीं है:

WHERE p.total IS NULL

purchases.id, purchases.name, purchases.total, p.id, p.name, p.total
2           , Tom           , 300
4           , Bob           , 500
6           , Alice         , 700

और यही वह जवाब है जिसकी हमें आवश्यकता है।







c# linq group-by