आइटम को सूची में सबसे ऊपर ले जाने के लिए LINQ का उपयोग करें


81

क्या LINQ का उपयोग करके किसी सूची में पहले आइटम के रूप में id = 10 के आइटम को स्थानांतरित करने का कोई तरीका है?

आइटम ए - आईडी = 5
आइटम बी - आईडी = १०
आइटम सी - आईडी = 12
आइटम डी - आईडी = 1

इस मामले में मैं अपने List<T>संग्रह के शीर्ष पर आइटम सी को सुरुचिपूर्ण ढंग से कैसे स्थानांतरित कर सकता हूं ?

मेरे पास अभी यही सबसे अच्छा है:

var allCountries = repository.GetCountries();
var topitem = allCountries.Single(x => x.id == 592);  
var finalList = new List<Country>();
finalList.Add(topitem);
finalList = finalList.Concat(allCountries.Where(x=> x.id != 592)).ToList();

क्या आप आइटम को शीर्ष आइटम के साथ स्वैप करना चाहते हैं या आइटम के नीचे आने तक सभी वस्तुओं को धक्का देकर आइटम को घुमाएंगे।
एंथनीवजोन

didn; t फ़ाइनलिस्ट .insert (0, "neww stuff"); काम
रोहित कुमार

जवाबों:


52

LINQ संग्रह को क्वेरी करने, मौजूदा प्रश्नों पर अनुमान बनाने या मौजूदा संग्रह के आधार पर नए प्रश्नों को उत्पन्न करने में मजबूत है। यह मौजूदा संग्रह इनलाइन को फिर से ऑर्डर करने के लिए एक उपकरण के रूप में नहीं है। उस प्रकार के ऑपरेशन के लिए हांडे प्रकार का उपयोग करना सबसे अच्छा है।

मान लें कि आपके पास नीचे के समान समान परिभाषा के साथ एक प्रकार है

class Item {
  public int Id { get; set; }
  ..
}

फिर निम्नलिखित प्रयास करें

List<Item> list = GetTheList();
var index = list.FindIndex(x => x.Id == 12);
var item = list[index];
list[index] = list[0];
list[0] = item;

4
+1 स्वैप परिदृश्य के लिए अच्छी तरह से काम करता है, मुझे लगता है कि 'वास्तव में एक बारी आवश्यक है'
एंथनीज्वंस

यह कमोबेश मैंने क्या किया है, लेकिन इस स्पष्टीकरण के लिए धन्यवाद कि क्यों प्रतीत होता है कि बेहतर तरीका नहीं है :)
qui

6
त्रुटि से निपटने के लिए, ध्यान दें कि आपको FindIndexपरिणाम मान की जांच करनी चाहिए , यह -1 है यदि आइटम सूची में नहीं मिला है।
श्नाइडर

क्या यह लक्ष्य तत्व को शीर्ष पर ले जाने के बजाय लक्ष्य तत्व सूचकांक के साथ पहले तत्व की अदला-बदली नहीं कर रहा है और बाकी सब कुछ नीचे ले जाना है?
फ्रॉस्टशोक्स

143

ज्ञात शीर्ष आइटम के अलावा, आप क्या ऑर्डर करना चाहते हैं? अगर आपको परवाह नहीं है, तो आप यह कर सकते हैं:

var query = allCountries.OrderBy(x => x.id != 592).ToList();

असल में, "असत्य" "सत्य" से पहले आता है ...

निश्चित रूप से मुझे नहीं पता कि यह LINQ में SQL आदि के लिए क्या करता है। आपको इसे डेटाबेस में ऑर्डर करने से रोकने की आवश्यकता हो सकती है:

var query = allCountries.AsEnumerable()
                        .OrderBy(x => x.id != 592)
                        .ToList();

1
LINQ से SQL के लिए अपेक्षित रूप से काम नहीं करता है। मैंने अभी इसका परीक्षण किया।
यासर शेख

5
+1 धन्यवाद जॉन। मैं नाम से ऑर्डर करना चाहता था, लेकिन आइटम को आईडी = 0 के साथ शीर्ष पर रखता था इसलिए मैंने ऐसा किया: allCountries.OrderBy (x => x.id == 0; "00000": x.Name) .ToList (); प्रदर्शन कोई समस्या नहीं है क्योंकि सूची छोटी है।
नीमा

3
बाद में कोड की समीक्षा करने वाले किसी व्यक्ति के लिए यह स्पष्ट नहीं हो सकता है कि बूलियन मानों को "गलत, सत्य" का आदेश दिया गया है। मैं इस पर अधिक क्रिया समाधानों की सिफारिश करूंगा।
rymdsmurf

1
सुंदर! मैं Nameशीर्ष या अनुक्रमणिका 0 पर एक छोटी सूची में चाहता था , LINQ में संस्थाओं के लिए, और इसने किया था धन्यवाद +1। db.Systms.Where(s => s.IsActive == true).OrderBy(x => x.SystemName != "Portal Administration").ToList();
इरफान

उत्तम सामग्री! एक अच्छा सरल उपाय। धन्यवाद,
ह्यूगो नवा कोप्प

43

Linq आम तौर पर Enumerables पर काम करता है, इसलिए अब यह नहीं है कि अंतर्निहित प्रकार एक संग्रह है। इसलिए सूची के शीर्ष पर आइटम को स्थानांतरित करने के लिए मैं कुछ का उपयोग करने का सुझाव दूंगा जैसे (यदि आपको ऑर्डर को संरक्षित करने की आवश्यकता है)

var idx = myList.FindIndex(x => x.id == 592);
var item = myList[idx];
myList.RemoveAt(idx);
myList.Insert(0, item);

यदि आपका फ़ंक्शन केवल IEnumerable देता है, तो आप ToList()इसे पहले सूची में बदलने के लिए विधि का उपयोग कर सकते हैं

यदि आप उस आदेश को संरक्षित नहीं करते हैं तो आप केवल स्थिति 0 और स्थिति idx पर मानों को स्वैप कर सकते हैं


यह केवल मूल्यों की अदला-बदली के बजाय घूमने के परिदृश्य के लिए एकदम सही है।
ब्रैडली माउंटफोर्ड

36
var allCountries = repository.GetCountries();
allCountries.OrderByDescending(o => o.id == 12).ThenBy(o => o.id) 

यह सूची के शीर्ष पर id = 12 के साथ ऑब्जेक्ट को सम्मिलित करेगा और आदेश को संरक्षित करते हुए, बाकी को नीचे घुमाएगा।


मुझे इस विचार प्रक्रिया से प्यार है, लेकिन डी के पास 1 की आईडी है, इसलिए क्या यह सी, डी, ए, बी के रूप में ऑर्डर नहीं करेगा?
डेविड

3
@PhatWrat ज़रूर, इसलिए अगर आप इससे बचना चाहते थे तो आप कहेंगे ।ThenBy (o => o.name) या कुछ इसी तरह का
Nick Gillum

1
शीर्ष उत्तर होना चाहिए! धन्यवाद
Mantisimo

10

यहाँ एक विस्तार विधि है जिसका आप उपयोग करना चाहते हैं। यह तत्व (एस) को स्थानांतरित करता है जो दिए गए विधेय को शीर्ष पर जोड़ता है, क्रम को संरक्षित करता है।

public static IEnumerable<T> MoveToTop(IEnumerable<T> list, Func<T, bool> func) {
    return list.Where(func)
               .Concat(list.Where(item => !func(item)));
}

जटिलता के संदर्भ में, मुझे लगता है कि यह संग्रह पर दो पास बना सकता है, इसे O (n) बना रहा है, जैसे इन्सर्ट / निकालें संस्करण, लेकिन जॉन स्कीट के ऑर्डरबाय सुझाव से बेहतर है।


2

आप बूलियन कुंजी के साथ दो समूहों में "समूह द्वारा" कर सकते हैं, और फिर उन्हें सॉर्ट कर सकते हैं

var finalList= allCountries
                .GroupBy(x => x.id != 592)
                .OrderBy(g => g.Key)
                .SelectMany(g => g.OrderBy(x=> x.id ));

2

मैं यह एक पुराना सवाल जानता हूं लेकिन मैंने इसे इस तरह किया है

class Program
{
    static void Main(string[] args)
    {
        var numbers = new int[] { 5, 10, 12, 1 };

        var ordered = numbers.OrderBy(num => num != 10 ? num : -1);

        foreach (var num in ordered)
        {
            Console.WriteLine("number is {0}", num);
        }

        Console.ReadLine();
    }
}

यह प्रिंट:

नंबर 10
नंबर है 1
नंबर है 5
नंबर 12 है


1
public static IEnumerable<T> ServeFirst<T>(this IEnumerable<T> source, 
    Predicate<T> p)
{
    var list = new List<T>();

    foreach (var s in source)
    {
        if (p(s))
            yield return s;
        else
            list.Add(s);
    }

    foreach (var s in list)
        yield return s;
}

1

किसी समस्या को हल करने की कोशिश करते समय आपको मिलने वाले दृष्टिकोणों की संख्या दिलचस्प है।

var service = AutogateProcessorService.GetInstance();
var allConfigs = service.GetAll();
allConfigs = allConfigs.OrderBy(c => c.ThreadDescription).ToList();
var systemQueue = allConfigs.First(c => c.AcquirerId == 0);
allConfigs.Remove(systemQueue);
allConfigs.Insert(0, systemQueue);

1

यह भी जांचने के लिए कि क्या वस्तु बिना अपवाद के पाई गई, कुछ इस तरह है:

var allCountries = repository.GetCountries();
var lookup = allCountries.ToLookup(x => x.id == 592);  
var finalList = lookup[true].Concat(lookup[false]).ToList();
if ( lookup[true].Count() != 1 ) YouAreInTrouble();

0

मैंने ऐसा करने के लिए एक स्थैतिक विस्तार विधि लिखी। ध्यान दें कि यह ऑर्डर को संरक्षित नहीं करता है, यह केवल आइटम को स्वैप करता है। यदि आपको आदेश को संरक्षित करने की आवश्यकता है, तो आपको एक घुमा देना चाहिए एक साधारण स्वैप नहीं।

/// <summary>
/// Moves the item to the front of the list if it exists, if it does not it returns false
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="collection"></param>
/// <param name="predicate"></param>
/// <returns></returns>
public static bool MoveToFrontOfListWhere<T>(this List<T> collection, Func<T, bool> predicate)
{
    if (collection == null || collection.Count <= 0) return false;

    int index = -1;
    for (int i = 0; i < collection.Count; i++)
    {
        T element = collection.ElementAt(i);
        if (!predicate(element)) continue;
        index = i;
        break;
    }

    if (index == -1) return false;

    T item = collection[index];
    collection[index] = collection[0];
    collection[0] = item;
    return true;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.