LINQ का उपयोग करके अनुक्रम में सभी लेकिन अंतिम तत्व कैसे लें?


131

मान लीजिए कि मेरे पास एक अनुक्रम है।

IEnumerable<int> sequence = GetSequenceFromExpensiveSource();
// sequence now contains: 0,1,2,3,...,999999,1000000

अनुक्रम प्राप्त करना सस्ता नहीं है और गतिशील रूप से उत्पन्न होता है, और मैं केवल एक बार इसके माध्यम से पुनरावृति करना चाहता हूं।

मैं 0 - 999999 प्राप्त करना चाहता हूं (अर्थात सब कुछ लेकिन अंतिम तत्व)

मैं मानता हूं कि मैं कुछ ऐसा कर सकता था:

sequence.Take(sequence.Count() - 1);

लेकिन बड़े अनुक्रम में दो गणना में परिणाम है।

वहाँ एक LINQ निर्माण है जो मुझे करने देता है:

sequence.TakeAllButTheLastElement();

3
आपको एक O (2n) समय या O (गणना) स्थान दक्षता एल्गोरिदम के बीच चयन करना है, जहां बाद वाले को आंतरिक सरणी में आइटम स्थानांतरित करने की आवश्यकता होती है।
डाइकैम

1
डारियो, क्या आप किसी ऐसे व्यक्ति के लिए व्याख्या करेंगे जो बड़े ओ-नोटेशन में नहीं है?
16

इस डुप्लिकेट प्रश्न को भी देखें: stackoverflow.com/q/4166493/240733
stakx -

मैंने सूची को संग्रह में परिवर्तित करके और फिर कॉल करके इसे समाप्त कर दिया sequenceList.RemoveAt(sequence.Count - 1);। मेरे मामले में यह स्वीकार्य है क्योंकि सभी LINQ जोड़तोड़ के बाद मुझे इसे सरणी या IReadOnlyCollectionवैसे भी परिवर्तित करना होगा । मुझे आश्चर्य है कि आपका उपयोग मामला क्या है जहां आप कैशिंग पर भी विचार नहीं करते हैं? जैसा कि मैं देख सकता हूं कि स्वीकृत उत्तर भी कुछ कैशिंग इतना सरल रूपांतरित करता Listहै जो मेरी राय में बहुत आसान और छोटा है।
पावेल्स अहमुलिंस

जवाबों:


64

मैं एक Linq समाधान नहीं जानता - लेकिन आप जनरेटर (उपज वापसी) का उपयोग करके आसानी से एल्गोरिथ्म को स्वयं कोड कर सकते हैं।

public static IEnumerable<T> TakeAllButLast<T>(this IEnumerable<T> source) {
    var it = source.GetEnumerator();
    bool hasRemainingItems = false;
    bool isFirst = true;
    T item = default(T);

    do {
        hasRemainingItems = it.MoveNext();
        if (hasRemainingItems) {
            if (!isFirst) yield return item;
            item = it.Current;
            isFirst = false;
        }
    } while (hasRemainingItems);
}

static void Main(string[] args) {
    var Seq = Enumerable.Range(1, 10);

    Console.WriteLine(string.Join(", ", Seq.Select(x => x.ToString()).ToArray()));
    Console.WriteLine(string.Join(", ", Seq.TakeAllButLast().Select(x => x.ToString()).ToArray()));
}

या एक सामान्यीकृत समाधान के रूप में अंतिम n आइटम (टिप्पणियों में सुझाई गई एक कतार का उपयोग करके) को छोड़ देना:

public static IEnumerable<T> SkipLastN<T>(this IEnumerable<T> source, int n) {
    var  it = source.GetEnumerator();
    bool hasRemainingItems = false;
    var  cache = new Queue<T>(n + 1);

    do {
        if (hasRemainingItems = it.MoveNext()) {
            cache.Enqueue(it.Current);
            if (cache.Count > n)
                yield return cache.Dequeue();
        }
    } while (hasRemainingItems);
}

static void Main(string[] args) {
    var Seq = Enumerable.Range(1, 4);

    Console.WriteLine(string.Join(", ", Seq.Select(x => x.ToString()).ToArray()));
    Console.WriteLine(string.Join(", ", Seq.SkipLastN(3).Select(x => x.ToString()).ToArray()));
}

7
अब आप इसे सभी लेकिन अंतिम n लेने के लिए सामान्यीकृत कर सकते हैं?
एरिक लिपर्ट

4
अच्छा लगा। एक छोटी सी त्रुटि; कतार का आकार n + 1 से आरंभ किया जाना चाहिए क्योंकि कतार का अधिकतम आकार है।
एरिक लिपर्ट

ReSharper आपके कोड ( सशर्त अभिव्यक्ति में असाइनमेंट ) को नहीं समझता है लेकिन मुझे यह पसंद है +1
Грозный

44

अपनी खुद की विधि बनाने के विकल्प के रूप में और एक मामले में तत्व आदेश महत्वपूर्ण नहीं है, अगला काम करेगा:

var result = sequence.Reverse().Skip(1);

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

मुझे नहीं पता कि 'रिवर्स' विधि कैसे काम करती है, इसलिए मैं इसका उपयोग करने वाली मेमोरी के बारे में निश्चित नहीं हूं। लेकिन मैं दो पुनरावृत्तियों के बारे में सहमत हूं। इस पद्धति का उपयोग बड़े संग्रह पर या यदि कोई प्रदर्शन महत्वपूर्ण है, तो इसका उपयोग नहीं किया जाना चाहिए।
कामारेई

5
ठीक है, आप रिवर्स को कैसे लागू करेंगे ? क्या आप पूरे अनुक्रम को संग्रहीत किए बिना इसे करने के लिए सामान्य तरीके से समझ सकते हैं ?
एरिक लिपर्ट

2
मुझे यह पसंद है, और यह अनुक्रम को दो बार उत्पन्न नहीं करने के मानदंडों को पूरा करता है।
एमी बी

12
और इसके अलावा आपको इसे रखने के लिए पूरे अनुक्रम को फिर से उलटने की आवश्यकता होगी क्योंकि यह equence.Reverse().Skip(1).Reverse()एक अच्छा उपाय नहीं है
shashwat

42

क्योंकि मैं स्पष्ट रूप से Enumerator, यहां एक विकल्प का उपयोग करने का प्रशंसक नहीं हूं । ध्यान दें कि अवैध तर्कों को चेक को जल्दी से फेंकने के लिए आवश्यक है, बजाय चेक को स्थगित करने के जब तक कि अनुक्रम वास्तव में गणना नहीं किया जाता है।

public static IEnumerable<T> DropLast<T>(this IEnumerable<T> source)
{
    if (source == null)
        throw new ArgumentNullException("source");

    return InternalDropLast(source);
}

private static IEnumerable<T> InternalDropLast<T>(IEnumerable<T> source)
{
    T buffer = default(T);
    bool buffered = false;

    foreach (T x in source)
    {
        if (buffered)
            yield return buffer;

        buffer = x;
        buffered = true;
    }
}

एरिक लिपर्ट के सुझाव के अनुसार, यह आसानी से n आइटम को सामान्य करता है:

public static IEnumerable<T> DropLast<T>(this IEnumerable<T> source, int n)
{
    if (source == null)
        throw new ArgumentNullException("source");

    if (n < 0)
        throw new ArgumentOutOfRangeException("n", 
            "Argument n should be non-negative.");

    return InternalDropLast(source, n);
}

private static IEnumerable<T> InternalDropLast<T>(IEnumerable<T> source, int n)
{
    Queue<T> buffer = new Queue<T>(n + 1);

    foreach (T x in source)
    {
        buffer.Enqueue(x);

        if (buffer.Count == n + 1)
            yield return buffer.Dequeue();
    }
}

जहां मैं अब पैदावार के बजाय उपज देने से पहले बफर करता हूं , ताकि n == 0मामले को विशेष हैंडलिंग की आवश्यकता न हो।


पहले उदाहरण में, यह संभवत: कभी-कभी-थोड़ा-थोड़ा तेज़ होगा ताकि buffered=falseअसाइन करने से पहले दूसरे क्लॉज़ में सेट किया जा सके buffer। हालत वैसे भी पहले से ही जाँची जा रही है, लेकिन यह bufferedलूप के माध्यम से हर बार अनावश्यक रूप से सेट करने से बचना होगा ।
जेम्स

क्या कोई मुझे चयनित उत्तर के विरुद्ध इस के पेशेवरों / विपक्षों को बता सकता है?
सिनजई

इनपुट जांच में कमी वाले एक अलग तरीके से कार्यान्वयन होने का क्या फायदा है? इसके अलावा, मैं सिर्फ एकल कार्यान्वयन को छोड़ दूंगा और कई कार्यान्वयन को एक डिफ़ॉल्ट मान दूंगा।
jpmc26

@ jpmc26 एक अलग विधि में चेक के साथ, आपको वास्तव में उस पल की मान्यता मिल जाती है जिसे आप कॉल करते हैं DropLast। अन्यथा सत्यापन केवल तब होता है जब आप वास्तव में अनुक्रम (परिणाम पर पहली कॉल MoveNextपर IEnumerator) की गणना करते हैं । डिबग करने के लिए कोई मज़ेदार बात नहीं है जब उत्पन्न करने IEnumerableऔर वास्तव में इसे एन्यूमरेट करने के बीच कोड की एक मनमानी राशि हो सकती है। आजकल मैं InternalDropLastएक आंतरिक कार्य के रूप में लिखूंगा DropLast, लेकिन यह कार्यक्षमता C # में मौजूद नहीं थी जब मैंने यह कोड 9 साल पहले लिखा था।
जोरेन सेप

28

Enumerable.SkipLast(IEnumerable<TSource>, Int32)विधि नेट स्टैंडर्ड 2.1 में जोड़ा गया है। यह वही करता है जो आप चाहते हैं।

IEnumerable<int> sequence = GetSequenceFromExpensiveSource();

var allExceptLast = sequence.SkipLast(1);

से https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.skiplast

एक नया संग्रहणीय संग्रह लौटाता है जिसमें स्रोत संग्रह के अंतिम गणना तत्वों के साथ स्रोत से तत्व शामिल होते हैं।


2
MoreLinq में यह भी मौजूद है
लेपरकोन

SkipLast के लिए +1। जब से मैं हाल ही में .NET फ्रेमवर्क से आया हूँ, मुझे यह नहीं पता था और उन्होंने इसे वहाँ जोड़ने की जहमत नहीं उठाई।
PRMan

12

BCL (या MoreLinq मुझे विश्वास है) में कुछ भी नहीं है, लेकिन आप अपनी खुद की एक्सटेंशन विधि बना सकते हैं।

public static IEnumerable<T> TakeAllButLast<T>(this IEnumerable<T> source)
{
    using (var enumerator = source.GetEnumerator())
        bool first = true;
        T prev;
        while(enumerator.MoveNext())
        {
            if (!first)
                yield return prev;
            first = false;
            prev = enumerator.Current;
        }
    }
}

यह कोड काम नहीं करेगा ... शायद होना चाहिए if (!first)और first = falseअगर से बाहर निकालना चाहिए ।
कालेब

यह कोड बंद दिखता है। ऐसा लगता है कि तर्क ' prevपहले पुनरावृत्ति में असंबद्ध लौटाता है , और उसके बाद हमेशा के लिए'।
फिल मिलर

लगता है कि कोड में "समय संकलन" त्रुटि है। हो सकता है आप इसे सही करना चाहेंगे। लेकिन हाँ, हम एक एक्सटेंडर लिख सकते हैं जो एक बार पुनरावृत्त करता है और सभी को वापस करता है लेकिन अंतिम आइटम।
मनीष बसंतानी

@ कालेब: आप बिलकुल सही कह रहे हैं - मैंने इसे एक असली भीड़ में लिखा था! अब तय हो गया। @ एम्बी: एर्म, सुनिश्चित नहीं है कि आप किस कंपाइलर का उपयोग कर रहे हैं। मेरे पास कुछ नहीं था। : पी
नोल्डोरिन

@RobertSchmidt उफ़, हाँ। मैंने usingअब एक बयान जोड़ा ।
नोल्डोरिन

7

यह उपयोगी होगा यदि .NET फ्रेमवर्क को इस तरह से एक्सटेंशन विधि के साथ भेजा गया था।

public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source, int count)
{
    var enumerator = source.GetEnumerator();
    var queue = new Queue<T>(count + 1);

    while (true)
    {
        if (!enumerator.MoveNext())
            break;
        queue.Enqueue(enumerator.Current);
        if (queue.Count > count)
            yield return queue.Dequeue();
    }
}

3

जोरेन के सुरुचिपूर्ण समाधान पर थोड़ा विस्तार:

public static IEnumerable<T> Shrink<T>(this IEnumerable<T> source, int left, int right)
{
    int i = 0;
    var buffer = new Queue<T>(right + 1);

    foreach (T x in source)
    {
        if (i >= left) // Read past left many elements at the start
        {
            buffer.Enqueue(x);
            if (buffer.Count > right) // Build a buffer to drop right many elements at the end
                yield return buffer.Dequeue();    
        } 
        else i++;
    }
}
public static IEnumerable<T> WithoutLast<T>(this IEnumerable<T> source, int n = 1)
{
    return source.Shrink(0, n);
}
public static IEnumerable<T> WithoutFirst<T>(this IEnumerable<T> source, int n = 1)
{
    return source.Shrink(n, 0);
}

जहां पहले leftकई तत्वों को छोड़ने के लिए एक साधारण गिनती को आगे छोटा करें और पिछले rightकई तत्वों को छोड़ने के लिए एक ही त्याग दिया गया बफर ।


3

यदि आपके पास अपना स्वयं का एक्सटेंशन रोल करने का समय नहीं है, तो यहां एक तेज़ तरीका है:

var next = sequence.First();
sequence.Skip(1)
    .Select(s => 
    { 
        var selected = next;
        next = s;
        return selected;
    });

2

स्वीकृत उत्तर पर थोड़ी भिन्नता, जो (मेरे स्वाद के लिए) थोड़ी सरल है:

    public static IEnumerable<T> AllButLast<T>(this IEnumerable<T> enumerable, int n = 1)
    {
        // for efficiency, handle degenerate n == 0 case separately 
        if (n == 0)
        {
            foreach (var item in enumerable)
                yield return item;
            yield break;
        }

        var queue = new Queue<T>(n);
        foreach (var item in enumerable)
        {
            if (queue.Count == n)
                yield return queue.Dequeue();

            queue.Enqueue(item);
        }
    }

2

आप प्राप्त कर सकते हैं Countया Lengthएक गणनीय की है, जो ज्यादातर मामलों में आप कर सकते हैं, तो बसTake(n - 1)

सरणियों के साथ उदाहरण

int[] arr = new int[] { 1, 2, 3, 4, 5 };
int[] sub = arr.Take(arr.Length - 1).ToArray();

उदाहरण के साथ IEnumerable<T>

IEnumerable<int> enu = Enumerable.Range(1, 100);
IEnumerable<int> sub = enu.Take(enu.Count() - 1);

सवाल IEnumerables के बारे में है और आपका समाधान है कि ओपी बचने की कोशिश कर रहा है। आपके कोड का प्रदर्शन प्रभाव है।
नवफाल

1

सिर्फ .ToList<type>()सीक्वेंस पर ही क्यों न हो , फिर कॉल काउंट करें और लाइक करें जैसा आपने मूल रूप से किया था..लेकिन जब से इसे एक सूची में खींचा गया है, तो इसे दो बार एक महंगी गणना नहीं करनी चाहिए। सही?


1

इस समस्या के लिए मैं जिस समाधान का उपयोग करता हूं वह थोड़ा अधिक विस्तृत है।

मेरे उपयोग स्थिर वर्ग में एक विस्तार विधि शामिल है MarkEndजो T-items को -items में EndMarkedItem<T>रूपांतरित करता है। प्रत्येक तत्व एक अतिरिक्त के साथ चिह्नित है int, जो या तो 0 है ; या (यदि कोई अंतिम 3 मदों में विशेष रूप से रुचि रखता है) -3 , -2 , या -1 अंतिम 3 वस्तुओं के लिए।

यह अपने आप ही उपयोगी हो सकता है, उदाहरण के लिए , जब आप foreachअंतिम 2 को छोड़कर प्रत्येक तत्व के बाद अल्पविराम के साथ एक साधारण- लूप में एक सूची बनाना चाहते हैं , जिसके बाद एक संयोजन शब्द (जैसे " और ") के बाद दूसरा आइटम होता है या " या "), और अंतिम तत्व एक बिंदु के बाद।

अंतिम n आइटम के बिना पूरी सूची तैयार करने के लिए , विस्तार विधि ButLastबस उस EndMarkedItem<T>समय से अधिक पुनरावृत्त होती है EndMark == 0

यदि आप निर्दिष्ट नहीं करते हैं tailLength, तो केवल अंतिम आइटम को (में MarkEnd()) या गिराया गया है ButLast()

अन्य समाधानों की तरह, यह बफरिंग द्वारा काम करता है।

using System;
using System.Collections.Generic;
using System.Linq;

namespace Adhemar.Util.Linq {

    public struct EndMarkedItem<T> {
        public T Item { get; private set; }
        public int EndMark { get; private set; }

        public EndMarkedItem(T item, int endMark) : this() {
            Item = item;
            EndMark = endMark;
        }
    }

    public static class TailEnumerables {

        public static IEnumerable<T> ButLast<T>(this IEnumerable<T> ts) {
            return ts.ButLast(1);
        }

        public static IEnumerable<T> ButLast<T>(this IEnumerable<T> ts, int tailLength) {
            return ts.MarkEnd(tailLength).TakeWhile(te => te.EndMark == 0).Select(te => te.Item);
        }

        public static IEnumerable<EndMarkedItem<T>> MarkEnd<T>(this IEnumerable<T> ts) {
            return ts.MarkEnd(1);
        }

        public static IEnumerable<EndMarkedItem<T>> MarkEnd<T>(this IEnumerable<T> ts, int tailLength) {
            if (tailLength < 0) {
                throw new ArgumentOutOfRangeException("tailLength");
            }
            else if (tailLength == 0) {
                foreach (var t in ts) {
                    yield return new EndMarkedItem<T>(t, 0);
                }
            }
            else {
                var buffer = new T[tailLength];
                var index = -buffer.Length;
                foreach (var t in ts) {
                    if (index < 0) {
                        buffer[buffer.Length + index] = t;
                        index++;
                    }
                    else {
                        yield return new EndMarkedItem<T>(buffer[index], 0);
                        buffer[index] = t;
                        index++;
                        if (index == buffer.Length) {
                            index = 0;
                        }
                    }
                }
                if (index >= 0) {
                    for (var i = index; i < buffer.Length; i++) {
                        yield return new EndMarkedItem<T>(buffer[i], i - buffer.Length - index);
                    }
                    for (var j = 0; j < index; j++) {
                        yield return new EndMarkedItem<T>(buffer[j], j - index);
                    }
                }
                else {
                    for (var k = 0; k < buffer.Length + index; k++) {
                        yield return new EndMarkedItem<T>(buffer[k], k - buffer.Length - index);
                    }
                }
            }    
        }
    }
}

1
    public static IEnumerable<T> NoLast<T> (this IEnumerable<T> items) {
        if (items != null) {
            var e = items.GetEnumerator();
            if (e.MoveNext ()) {
                T head = e.Current;
                while (e.MoveNext ()) {
                    yield return head; ;
                    head = e.Current;
                }
            }
        }
    }

1

मुझे नहीं लगता कि इससे ज्यादा रसीद मिल सकती है - यह भी सुनिश्चित करना IEnumerator<T>:

public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
{
    using (var it = source.GetEnumerator())
    {
        if (it.MoveNext())
        {
            var item = it.Current;
            while (it.MoveNext())
            {
                yield return item;
                item = it.Current;
            }
        }
    }
}

संपादित करें: तकनीकी रूप से इस उत्तर के समान ।


1

C # 8.0 के साथ आप इसके लिए सीमाओं और सूचकांकों का उपयोग कर सकते हैं ।

var allButLast = sequence[..^1];

डिफ़ॉल्ट रूप से C # 8.0 के लिए .NET कोर 3.0 या .NET मानक 2.1 (या ऊपर) की आवश्यकता होती है। पुराने कार्यान्वयन के साथ उपयोग करने के लिए इस धागे की जाँच करें


0

आप लिख सकते हैं:

var list = xyz.Select(x=>x.Id).ToList();
list.RemoveAt(list.Count - 1);

0

यह एक सामान्य और IMHO सुरुचिपूर्ण समाधान है जो सभी मामलों को सही ढंग से संभाल लेगा:

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        IEnumerable<int> r = Enumerable.Range(1, 20);
        foreach (int i in r.AllButLast(3))
            Console.WriteLine(i);

        Console.ReadKey();
    }
}

public static class LinqExt
{
    public static IEnumerable<T> AllButLast<T>(this IEnumerable<T> enumerable, int n = 1)
    {
        using (IEnumerator<T> enumerator = enumerable.GetEnumerator())
        {
            Queue<T> queue = new Queue<T>(n);

            for (int i = 0; i < n && enumerator.MoveNext(); i++)
                queue.Enqueue(enumerator.Current);

            while (enumerator.MoveNext())
            {
                queue.Enqueue(enumerator.Current);
                yield return queue.Dequeue();
            }
        }
    }
}

-1

मेरा पारंपरिक IEnumerableदृष्टिकोण:

/// <summary>
/// Skips first element of an IEnumerable
/// </summary>
/// <typeparam name="U">Enumerable type</typeparam>
/// <param name="models">The enumerable</param>
/// <returns>IEnumerable of type skipping first element</returns>
private IEnumerable<U> SkipFirstEnumerable<U>(IEnumerable<U> models)
{
    using (var e = models.GetEnumerator())
    {
        if (!e.MoveNext()) return;
        for (;e.MoveNext();) yield return e.Current;
        yield return e.Current;
    }
}

/// <summary>
/// Skips last element of an IEnumerable
/// </summary>
/// <typeparam name="U">Enumerable type</typeparam>
/// <param name="models">The enumerable</param>
/// <returns>IEnumerable of type skipping last element</returns>
private IEnumerable<U> SkipLastEnumerable<U>(IEnumerable<U> models)
{
    using (var e = models.GetEnumerator())
    {
        if (!e.MoveNext()) return;
        yield return e.Current;
        for (;e.MoveNext();) yield return e.Current;
    }
}

आपका SkipLastEnumerable पारंपरिक हो सकता है, लेकिन टूटा हुआ है। यह पहला तत्व है जो हमेशा अपरिभाषित यू होता है - तब भी जब "मॉडल" में 1 तत्व होता है। बाद के मामले में, मैं एक खाली परिणाम की उम्मीद करूंगा।
रॉबर्ट श्मिट

इसके अलावा, IEnumerator <T> IDisposable है।
रॉबर्ट श्मिट

यह सच है / उल्लेख किया। धन्यवाद।
चिब्यूज ओपटा

-1

एक सरल तरीका यह होगा कि आप केवल एक कतार में बदल जाएं और तब तक छल करें, जब तक कि आप जिस आइटम को छोड़ना चाहते हैं, वह केवल छोड़ दिया गया हो।

public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source, int n)
{
    var queue = new Queue<T>(source);

    while (queue.Count() > n)
    {
        yield return queue.Dequeue();
    }
}

वहाँ है ले मदों की ज्ञात संख्या ले जाते थे। और बड़े पर्याप्त enumerable के लिए कतार भयानक है।
सिनट्राड

-2

हो सकता है:

var allBuLast = sequence.TakeWhile(e => e != sequence.Last());

मुझे लगता है कि यह डे "कहां" जैसा होना चाहिए लेकिन ऑर्डर को संरक्षित करना (?)।


3
यह एक बहुत ही अक्षम तरीका है। अनुक्रम का मूल्यांकन करने के लिए। () इसे पूरे अनुक्रम को पार करना है, क्रम में प्रत्येक तत्व के लिए ऐसा करना है। O (n ^ 2) दक्षता।
माइक

तुम सही हो। मुझे नहीं पता कि मैं क्या सोच रहा था जब मैंने यह एक्सडी लिखा था। वैसे भी, क्या आप सुनिश्चित हैं कि अंतिम () पूरे अनुक्रम को पार कर जाएगा? IEnumerable (जैसे एरे) के कुछ कार्यान्वयन के लिए, यह O (1) होना चाहिए। मैंने सूची के कार्यान्वयन की जाँच नहीं की, लेकिन इसमें अंतिम तत्व में शुरू होने वाला एक "रिवर्स" चलना भी हो सकता है, जो O (1) भी लेगा। इसके अलावा, आपको यह ध्यान रखना चाहिए कि O (n) = O (2n), कम से कम तकनीकी रूप से बोल रहा हो। इसलिए, यदि यह प्रक्रिया आपके ऐप्स प्रदर्शन के लिए बिल्कुल आलोचक नहीं है, तो मैं बहुत स्पष्ट अनुक्रम के साथ चिपका रहूँगा। (अनुक्रम ।ाउंट () - 1)।
गिलर्मो एरेस

@ माइक मैं आपसे सहमत नहीं हूँ, अनुक्रम .ast () O (1) है ताकि इसे पूरे अनुक्रम को पार करने की आवश्यकता न हो। stackoverflow.com/a/1377895/812598
GoRoS

1
@GoRoS, यह केवल O (1) है यदि अनुक्रम ICollection / IList को लागू करता है या एक ऐरे है। अन्य सभी क्रम ओ (एन) हैं। मेरे सवाल में, मैं यह नहीं मानता कि ओ (1) के स्रोतों में से एक
माइक

3
अनुक्रम में कई आइटम हो सकते हैं जो इस स्थिति को संतुष्ट करते हैं ई == अनुक्रम। (), उदाहरण के लिए नया [] {1, 1, 1, 1}
सर्गेई शैंडर

-2

यदि गति की आवश्यकता है, तो स्कूल का यह पुराना तरीका सबसे तेज़ होना चाहिए, भले ही कोड उतना सुचारू नहीं दिखता हो जितना कि लिनक इसे बना सकता है।

int[] newSequence = int[sequence.Length - 1];
for (int x = 0; x < sequence.Length - 1; x++)
{
    newSequence[x] = sequence[x];
}

यह आवश्यक है कि अनुक्रम एक सरणी है क्योंकि इसमें एक निश्चित लंबाई और अनुक्रमित आइटम हैं।


2
आप एक IEnumerable के साथ काम कर रहे हैं जो एक सूचकांक के माध्यम से तत्वों तक पहुंच की अनुमति नहीं देता है। आपका हल काम नहीं करता है। यह मानते हुए कि आप इसे सही करते हैं, इसके लिए लंबाई निर्धारित करने के लिए अनुक्रम की आवश्यकता होती है, लंबाई n-1 की एक सरणी आवंटित करते हुए, सभी तत्वों को कॉपी करते हुए। - 1. 2 एन -1 ऑपरेशन और (2 एन -1) * (4 या 8 बाइट्स) मेमोरी। वह भी तेज नहीं है।
तारिक

-4

मैं शायद ऐसा कुछ करूंगा:

sequence.Where(x => x != sequence.LastOrDefault())

यह एक जांच के साथ एक पुनरावृत्ति है कि यह हर बार के लिए अंतिम नहीं है।


3
दो कारण जो अच्छी बात नहीं है। 1) .LastOrDefault () पूरे अनुक्रम को पुनरावृत्त करने की आवश्यकता है, और कहा जाता है कि प्रत्येक तत्व के लिए अनुक्रम में (.Where ())। 2) यदि अनुक्रम [1,2,1,2,1,2] है और आपने अपनी तकनीक का उपयोग किया है, तो आपको [1,1,1] छोड़ दिया जाएगा।
माइक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.