अन्य सूची आईडी से एक सूची को क्रमबद्ध करें


150

मेरे पास इस तरह के कुछ पहचानकर्ताओं के साथ एक सूची है:

List<long> docIds = new List<long>() { 6, 1, 4, 7, 2 };

Morover, मेरे पास <T>मदों की एक और सूची है , जो ऊपर वर्णित आईडी द्वारा दर्शाए गए हैं।

List<T> docs = GetDocsFromDb(...)

मुझे दोनों संग्रहों में समान क्रम रखने की आवश्यकता है, ताकि आइटम List<T>पहले की तुलना में उसी स्थिति में हों (खोज इंजन स्कोरिंग कारणों के कारण)। और यह प्रक्रिया GetDocsFromDb()फ़ंक्शन में नहीं की जा सकती ।

यदि आवश्यक हो, तो दूसरी सूची को कुछ अन्य संरचना में बदलना संभव है ( Dictionary<long, T>उदाहरण के लिए), लेकिन मैं इसे बदलना नहीं चाहूंगा।

LINQ के साथ "कुछ IDs के आधार पर" यह अलंकरण करने का कोई सरल और कुशल तरीका है?


क्या आप आश्वस्त हैं कि हर docIdबार ठीक एक बार होता है docs, क्या संपत्ति होगी Idया चयनकर्ता की Func<T, long>आवश्यकता होगी?
जोड्रेल

क्या पहली सूची एक "मास्टर सूची" का प्रतिनिधित्व करती है? एक और शब्द, क्या दूसरी सूची पहली सूची के एक हिस्से (या संपूर्णता) का प्रतिनिधित्व करने वाला एक उपसमुच्चय होगी?
16 सितंबर को code4life

जवाबों:


332
docs = docs.OrderBy(d => docsIds.IndexOf(d.Id)).ToList();

@ कफ यही कारण है कि मैंने भी अपवित्र किया, दस्तावेज आईडी संपत्ति को जानने के लिए निर्भर करता है Id। यह प्रश्न में निर्दिष्ट नहीं है।
जोड्रेल

3
@ BorjaLópez, एक त्वरित नोट। आप अपने प्रश्न में दक्षता का उल्लेख करते हैं। IndexOfआपके उदाहरण के लिए पूरी तरह से स्वीकार्य है और अच्छा और सरल है। यदि आपके पास बहुत अधिक डेटा था तो मेरा उत्तर बेहतर अनुकूल हो सकता है। stackoverflow.com/questions/3663014/…
जोड्रेल

2
@DenysDenysenko शानदार। बहुत बहुत धन्यवाद; ठीक वही जो मेरे द्वारा खोजा जा रहा था।
रेशमकीट

3
यदि आपके पास ऐसे डॉक्स में तत्व नहीं हैं जो ऑर्डर करने की सूची में आईडी नहीं रखते हैं
डैन ह्यूनक्स

4
काफी अयोग्य - IndexOf को स्रोत संग्रह में प्रत्येक तत्व के लिए बुलाया जा रहा है और तत्वों को ऑर्डर करने के लिए OrderBy को आदेश देना है। @Jodrell द्वारा समाधान बहुत तेज है।
sdds 14

25

चूंकि आप निर्दिष्ट नहीं करते हैं T,

IEnumerable<T> OrderBySequence<T, TId>(
       this IEnumerable<T> source,
       IEnumerable<TId> order,
       Func<T, TId> idSelector)
{
    var lookup = source.ToDictionary(idSelector, t => t);
    foreach (var id in order)
    {
        yield return lookup[id];
    }
}

क्या आप चाहते हैं के लिए एक सामान्य विस्तार है।

आप शायद इस तरह से एक्सटेंशन का उपयोग कर सकते हैं,

var orderDocs = docs.OrderBySequence(docIds, doc => doc.Id);

एक सुरक्षित संस्करण हो सकता है

IEnumerable<T> OrderBySequence<T, TId>(
       this IEnumerable<T> source,
       IEnumerable<TId> order,
       Func<T, TId> idSelector)
{
    var lookup = source.ToLookup(idSelector, t => t);
    foreach (var id in order)
    {
        foreach (var t in lookup[id])
        {
           yield return t;
        }
    }
}

अगर sourceठीक से ज़िप नहीं करता है तो काम करेगा order


मैंने इस समाधान का उपयोग किया और यह काम किया। बस, मुझे विधि को स्थिर और वर्ग को स्थिर बनाना था।
विनम

5

जोडरेल का जवाब सबसे अच्छा है, लेकिन वास्तव में उन्होंने इसे फिर से लागू किया System.Linq.Enumerable.Join। ज्वाइन भी लुकअप का उपयोग करता है और स्रोत के आदेश रखता है।

    docIds.Join(
      docs,
      i => i,
      d => d.Id,
      (i, d) => d);

यही कारण है कि इस सवाल का जवाब हम देख रहे है
Orace

2
यह सिर्फ यह साबित करता है कि जुड़ना समझना बहुत मुश्किल है क्योंकि सभी ने इस बात पर सहमति व्यक्त की कि इसे फिर से लिखना आसान था।
PRMan

-3

एक सरल तरीका है क्रम क्रम के साथ ज़िप करना:

List<T> docs = GetDocsFromDb(...).Zip(docIds, Tuple.Create)
               .OrderBy(x => x.Item2).Select(x => x.Item1).ToList();

क्यों एक ज़िप के बाद आदेश?
जोडरेल

क्योंकि Zipसंबंधित सूची में एक ही स्थिति में दस्तावेज़ के साथ प्रत्येक सूचकांक (एक ट्यूपल में) को जोड़ती है। फिर ऑर्डरबाय इंडेक्स भाग द्वारा ट्यूपल्स को छांटता है और फिर चुनिंदा डॉक्स को अब ऑर्डर की गई सूची से खोदता है।
अल्बिन सुन्नान्बो

लेकिन, GetDocsFromDb का परिणाम अनियंत्रित हो जाता है, इसलिए आप Tuples बना सकते हैं जहां Item1से संबंधित नहीं है Item2
जॉड्रेल

1
मुझे लगता है कि यह अप्पन आईडी के आदेश देने के बाद से गलत परिणाम देगा और सूचकांक नहीं।
माइकल लॉगुतोव
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.