मैं सूची <T> से प्रत्येक nth आइटम कैसे प्राप्त कर सकता हूं?


115

मैं .NET 3.5 का उपयोग कर रहा हूं और nएक सूची से प्रत्येक * * आइटम प्राप्त करने में सक्षम होना चाहता हूं । मैं इस बात से परेशान नहीं हूं कि क्या यह लंबोदर अभिव्यक्ति या LINQ का उपयोग करके हासिल किया गया है।

संपादित करें

ऐसा लगता है कि यह प्रश्न काफी बहस को उकसाया (जो कि एक अच्छी बात है, ठीक है?)। मुख्य बात मैंने सीखा है कि जब आप सोचते हैं कि आप कुछ करने के लिए हर तरह से जानते हैं (भले ही यह उतना ही सरल हो), फिर से सोचें!


मैंने आपके मूल प्रश्न के पीछे कोई अर्थ नहीं निकाला है; मैंने केवल इसे साफ किया और कैपिटलाइज़ेशन और विराम चिह्न का सही इस्तेमाल किया। (.NET कैपिटलाइज़्ड है, LINQ ऑल-कैप्स में है, और यह 'लैम्ब्डा' नहीं है, यह 'लैम्डा एक्सप्रेशन' है।)
जॉर्ज स्टॉकर

1
आपने "फ़्यूस्ड" को "सुनिश्चित" से बदल दिया जो सभी समानार्थक शब्द नहीं हैं।
MQP

ऐसा लगता होगा। यकीन होने से कोई मतलब नहीं है, जब तक कि "मुझे यकीन नहीं है कि अगर यह प्रयोग करने योग्य है ..."
शमूएल

हां, जैसा कि मैं इसे समझता हूं, यह सही है।
mqp

fussed को संभवतः "संबंधित" के साथ प्रतिस्थापित किया जाना सबसे अच्छा होगा ताकि यह पढ़े "मुझे यह चिंता नहीं है कि क्या यह लंबोदर अभिव्यक्ति या LINQ का उपयोग करके हासिल किया गया है।"
theTXI

जवाबों:


190
return list.Where((x, i) => i % nStep == 0);

5
@ उत्तर: ध्यान दें कि यह वास्तव में आपको nth - 1 तत्व देगा। यदि आप वास्तविक nth एलिमेंट्स (पहले लंघन) चाहते हैं तो आपको 1 से i जोड़ना होगा।
कैस्पर ओने

2
हां, मुझे लगता है कि यह निर्भर करता है कि आप "एनटी" से क्या मतलब है, लेकिन आपकी व्याख्या अधिक सामान्य हो सकती है। अपनी आवश्यकताओं के अनुरूप i से जोड़ें या घटाएं।
mqp

5
बस ध्यान दें: निश्चित वृद्धि के साथ एक साधारण लूप की तुलना में लाइनक / लैंबडा समाधान बहुत कम प्रदर्शनकारी होगा।
मार्टिनस्टैटनर

5
जरूरी नहीं कि आस्थगित निष्पादन के साथ ही इसे फॉरेस्ट लूप में इस्तेमाल किया जा सके और मूल सूची में केवल एक बार ही लूप हो।
शमूएल

1
यह निर्भर करता है कि आप "व्यावहारिक" से क्या मतलब है। यदि आपको उपयोगकर्ता द्वारा एक बटन क्लिक करने पर 30 आइटमों की सूची में हर दूसरे आइटम को प्राप्त करने के लिए एक त्वरित तरीके की आवश्यकता है, तो मैं कहूंगा कि यह व्यावहारिक रूप से हर बिट है। कभी-कभी प्रदर्शन वास्तव में अब कोई मायने नहीं रखते। बेशक, कभी-कभी ऐसा होता है।
१q:

37

मुझे पता है कि यह "पुराना स्कूल" है, लेकिन बस स्टेपिंग = एन के साथ लूप के लिए उपयोग क्यों नहीं करें?


यह मूल रूप से मेरा विचार था।
मार्क पिम

1
@ मिचेल टॉड: यह काम करता है, लेकिन इसके साथ समस्या यह है कि आपको हर जगह उस कार्यक्षमता की नकल करनी होगी। LINQ का उपयोग करके, यह रचित क्वेरी का हिस्सा बन जाता है।
कैस्पर ओने

8
@casperOne: मेरा मानना ​​है कि प्रोग्रामर्स ने इससे निपटने के लिए सबरूटीन्स नामक इस चीज़ का आविष्कार किया था;) एक वास्तविक कार्यक्रम में, मैं शायद एक लूप का उपयोग करूँगा, चतुर LINQ संस्करण के बावजूद, क्योंकि एक लूप का मतलब है कि आपको हर तत्व पर पुनरावृत्ति नहीं करनी है ( एन। द्वारा सूचकांक वृद्धि)
mqp

मैं सहमत हूं कि पुराने स्कूल समाधान के लिए जाना है, और मैं यह भी अनुमान लगा रहा हूं कि यह बेहतर प्रदर्शन करेगा।
जेसपर फेयर नुड्सन

फैंसी नए वाक्यविन्यास के साथ दूर ले जाने के लिए आसान है। हालांकि इसका मज़ा।
रॉनी

34

लगता है

IEnumerator<T> GetNth<T>(List<T> list, int n) {
  for (int i=0; i<list.Count; i+=n)
    yield return list[i]
}

चालबाजी करेगा। मुझे Linq या एक लैम्ब्डा अभिव्यक्ति का उपयोग करने की आवश्यकता नहीं दिखती है।

संपादित करें:

इसे बनाओ

public static class MyListExtensions {
  public static IEnumerable<T> GetNth<T>(this List<T> list, int n) {
    for (int i=0; i<list.Count; i+=n)
      yield return list[i];
  }
}

और आप एक LINQish तरीके से लिखते हैं

from var element in MyList.GetNth(10) select element;

दूसरा संपादन :

इसे और भी बेहतर बनाने के लिए

from var i in Range(0, ((myList.Length-1)/n)+1) select list[n*i];

2
मुझे इस ([) विधि के बजाय, () विधि का उपयोग करने के लिए यह तरीका पसंद है, जो अनिवार्य रूप से IEnumable के हर तत्व को पुनरावृत्त करता है। यदि आपके पास IList / ICollection प्रकार है, तो यह बेहतर तरीका है, IMHO।
स्पॉल्सन

यह सुनिश्चित नहीं है कि सूची कैसे काम करती है, लेकिन आप लूप का उपयोग क्यों करते हैं और list[i]बदले में सिर्फ वापसी करते हैं list[n-1]?
जुआन कार्लोस ओरोपेज़ा

@JuanCarlosOropeza वह हर nth तत्व (जैसे 0, 3, 6 ...) देता है, न कि केवल सूची का nth तत्व।
अल्फोक्स

27

आप उस अधिभार का उपयोग कर सकते हैं जो तत्व के साथ सूचकांक को पास करता है

var everyFourth = list.Where((x,i) => i % 4 == 0);

1
कहना होगा कि मैं इस विधि का प्रशंसक हूं।
क्विंटन रॉबिन्सन

1
मैं भूल जाता हूं कि आप ऐसा कर सकते हैं - बहुत अच्छा।
स्टीफन न्यूमैन

10

पाश के लिए

for(int i = 0; i < list.Count; i += n)
    //Nth Item..

गणना गणना करने योग्य का मूल्यांकन करेगी। यदि यह linq के अनुकूल तरीके से किया गया था, तो आप lazily eval कर सकते हैं और पहले 100 मान ले सकते हैं जैसे `` source.TakeEvery (5) .Take (100) `` यदि अंतर्निहित स्रोत eval करने के लिए महंगा था, तो आपका दृष्टिकोण हर कारण होगा। मूल्यांकन किया जाने वाला तत्व
RhysC

1
@RhysC अच्छा बिंदु, सामान्य रूप से गणना के लिए। OTOH, प्रश्न निर्दिष्ट किया था List<T>, इसलिए Countसस्ते होने के लिए परिभाषित किया गया है।
टूलमेकर

3

मुझे यकीन नहीं है कि यह LINQ अभिव्यक्ति के साथ करना संभव है, लेकिन मुझे पता है कि आप इसे करने के लिए Whereएक्सटेंशन विधि का उपयोग कर सकते हैं । उदाहरण के लिए हर पांचवां आइटम पाने के लिए:

List<T> list = originalList.Where((t,i) => (i % 5) == 0).ToList();

यह पहला आइटम और वहां से हर पांचवां मिलेगा। यदि आप पहले के बजाय पांचवें आइटम पर शुरू करना चाहते हैं, तो आप 0 के साथ तुलना करने के बजाय 4 के साथ तुलना करते हैं।


3

मुझे लगता है कि यदि आप एक linq एक्सटेंशन प्रदान करते हैं, तो आपको कम से कम विशिष्ट इंटरफ़ेस पर काम करने में सक्षम होना चाहिए, इस प्रकार IEnumerable पर। बेशक, यदि आप विशेष रूप से बड़े एन के लिए गति के लिए हैं, तो आप अनुक्रमित पहुंच के लिए एक अधिभार प्रदान कर सकते हैं। उत्तरार्द्ध आवश्यक डेटा की बड़ी मात्रा में पुनरावृत्ति की आवश्यकता को हटाता है, और जहां क्लॉज की तुलना में बहुत तेज होगा। दोनों अधिभार प्रदान करने से कंपाइलर सबसे उपयुक्त संस्करण का चयन करता है।

public static class LinqExtensions
{
    public static IEnumerable<T> GetNth<T>(this IEnumerable<T> list, int n)
    {
        if (n < 0)
            throw new ArgumentOutOfRangeException("n");
        if (n > 0)
        {
            int c = 0;
            foreach (var e in list)
            {
                if (c % n == 0)
                    yield return e;
                c++;
            }
        }
    }
    public static IEnumerable<T> GetNth<T>(this IList<T> list, int n)
    {
        if (n < 0)
            throw new ArgumentOutOfRangeException("n");
        if (n > 0)
            for (int c = 0; c < list.Count; c += n)
                yield return list[c];
    }
}

यह किसी भी सूची के लिए काम करता है? क्योंकि मैं एक कस्टम वर्ग के लिए एक सूची में उपयोग करने की कोशिश करता हूं और एक IEnumarted <class> को <class> और मजबूर करने के बजाय coversion (वर्ग) List.GetNth (1) को वापस नहीं करता हूं।
जुआन कार्लोस ओरोपेजा

क्या मेरी गलती थी कि मुझे GetNth (1)। FirstOrDefault () शामिल करना होगा;
जुआन कार्लोस ओरोपेजा

0
private static readonly string[] sequence = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15".Split(',');

static void Main(string[] args)
{
    var every4thElement = sequence
      .Where((p, index) => index % 4 == 0);

    foreach (string p in every4thElement)
    {
        Console.WriteLine("{0}", p);
    }

    Console.ReadKey();
}

उत्पादन

यहां छवि विवरण दर्ज करें


0

Imho कोई जवाब नहीं सही है। सभी समाधान 0. से शुरू होते हैं, लेकिन मैं असली nth तत्व रखना चाहता हूं

public static IEnumerable<T> GetNth<T>(this IList<T> list, int n)
{
    for (int i = n - 1; i < list.Count; i += n)
        yield return list[i];
}

0

@belucha मुझे यह पसंद है, क्योंकि क्लाइंट कोड बहुत पठनीय है और कंपाइलर सबसे कुशल कार्यान्वयन को चुनता है। मैं आवश्यकताओं को कम करके IReadOnlyList<T>और उच्च-प्रदर्शन LINQ के लिए डिवीजन को बचाने के लिए इसका निर्माण करूंगा :

    public static IEnumerable<T> GetNth<T>(this IEnumerable<T> list, int n) {
        if (n <= 0) throw new ArgumentOutOfRangeException(nameof(n), n, null);
        int i = n;
        foreach (var e in list) {
            if (++i < n) { //save Division
                continue;
            }
            i = 0;
            yield return e;
        }
    }

    public static IEnumerable<T> GetNth<T>(this IReadOnlyList<T> list, int n
        , int offset = 0) { //use IReadOnlyList<T>
        if (n <= 0) throw new ArgumentOutOfRangeException(nameof(n), n, null);
        for (var i = offset; i < list.Count; i += n) {
            yield return list[i];
        }
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.