কোনও সংগ্রহের শেষ এন উপাদানগুলি পেতে লিনাক ব্যবহার করছেন?


284

একটি সংগ্রহ দেওয়া হয়েছে, সেই সংগ্রহের শেষ এন উপাদানগুলি পাওয়ার কোনও উপায় আছে? ফ্রেমওয়ার্কে যদি কোনও পদ্ধতি না থাকে তবে এটি করার জন্য কোনও এক্সটেনশন পদ্ধতি লেখার সর্বোত্তম উপায় কী হবে?

উত্তর:


422
collection.Skip(Math.Max(0, collection.Count() - N));

এই পদ্ধতির কোনও বাছাইয়ের উপর নির্ভরতা ছাড়াই আইটেম অর্ডার সংরক্ষণ করা হয় এবং বেশ কয়েকটি লিনকিউ সরবরাহকারীদের জুড়ে বিস্তৃত সামঞ্জস্য।

Skipনেতিবাচক নম্বর দিয়ে কল না করার জন্য যত্ন নেওয়া গুরুত্বপূর্ণ । কিছু সরবরাহকারী যেমন এন্টি ফ্রেমওয়ার্ক, যখন একটি নেতিবাচক যুক্তি উপস্থাপন করা হয় তখন একটি আর্গুমেন্ট এক্সেকশন তৈরি করবে। Math.Maxএই পরিষ্কার এড়ানোর জন্য কল ।

নীচের শ্রেণিতে এক্সটেনশন পদ্ধতিগুলির জন্য প্রয়োজনীয় সমস্ত প্রয়োজনীয় রয়েছে, যা হ'ল: একটি স্ট্যাটিক শ্রেণি, একটি স্থির পদ্ধতি এবং thisকীওয়ার্ডের ব্যবহার ।

public static class MiscExtensions
{
    // Ex: collection.TakeLast(5);
    public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int N)
    {
        return source.Skip(Math.Max(0, source.Count() - N));
    }
}

কর্মক্ষমতা সম্পর্কে একটি সংক্ষিপ্ত নোট:

যেহেতু কলটি Count()নির্দিষ্ট কিছু ডেটা স্ট্রাকচারের গণনা ঘটাতে পারে, এই পদ্ধতির মাধ্যমে ডেটা ধরে দুটি পাস হওয়ার ঝুঁকি রয়েছে। এটি বেশিরভাগ গণনার ক্ষেত্রে আসলেই সমস্যা নয়; আসলে, Count()ও (1) সময়ের মধ্যে অপারেশনটি মূল্যায়ন করতে তালিকাগুলি, অ্যারে এবং এমনকি ইএফ প্রশ্নের জন্য ইতিমধ্যে অপ্টিমাইজেশন উপস্থিত রয়েছে ।

তবে, আপনাকে অবশ্যই একটি ফরওয়ার্ড-গুনে গণ্য করতে হবে এবং দুটি পাস করা এড়াতে চাইলে ল্যাসে ভি কার্লসেন বা মার্ক বাইয়ারের বর্ণনা মতো একটি পাসের অ্যালগরিদম বিবেচনা করুন । এই উভয় পদ্ধতিরই গণনার সময় আইটেম ধরে রাখতে অস্থায়ী বাফার ব্যবহার করা হয়, যা সংগ্রহের শেষে পাওয়া গেলে তা পাওয়া যায়।


2
+1, যেমন এটি লিঙ্ক থেকে সত্তা / এসকিউএল তে কাজ করে। আমি অনুমান করছি যে এটি জিন্স কুরানের কৌশলের চেয়ে লিনক অব অবজেক্টে আরও পারফরম্যান্স।
স্ট্রিপলিং ওয়ারিয়র

11
সংগ্রহের প্রকৃতির উপর নির্ভর করে। গণনা () ও (এন) হতে পারে।
জেমস কারান

3
@ জামেস: একেবারে সঠিক। আইনিম্যারেবল সংগ্রহের সাথে যদি কঠোরভাবে কাজ করে তবে এটি একটি দ্বি-পাসের ক্যোয়ারী হতে পারে। আমি গ্যারান্টিযুক্ত 1-পাসের অ্যালগরিদমটি দেখতে আগ্রহী। এটি দরকারী হতে পারে।
কেব্রিমিংটন

4
কিছু মানদণ্ড করেছেন। এটি লিনকিউ-তে পরিণত হয়েছে আপনি যে ধরণের সংগ্রহ ব্যবহার করছেন তার উপর ভিত্তি করে অবজেক্টস কিছু অপ্টিমাইজেশন সম্পাদন করে। অ্যারে, Listগুলি এবং LinkedListগুলি ব্যবহার করে জেমসের সমাধানটি দ্রুততর হতে থাকে, যদিও আকারের দ্বারা নয় by আইইনামেবলকে যদি গণনা করা হয় (এনিউমারেবল। রেঞ্জের মাধ্যমে), তবে জেমসের সমাধানটি আরও বেশি সময় নেয়। বাস্তবায়ন সম্পর্কে কিছু না জেনে বা ভিন্ন ডেটা কাঠামোতে মানগুলি অনুলিপি না করে আমি একক পাসের গ্যারান্টি দেওয়ার কোনও উপায় সম্পর্কে ভাবতে পারি না।
স্ট্রিপলিং ওয়ারিয়র

1
@ রেডফিল্টার - যথেষ্ট ফর্সা। আমি মনে করি আমার পেজিং অভ্যাসগুলি এখানে ফাঁস হয়ে গেছে। আপনার আগ্রহী চোখের জন্য ধন্যবাদ।
kbrimington

59
coll.Reverse().Take(N).Reverse().ToList();


public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> coll, int N)
{
    return coll.Reverse().Take(N).Reverse();
}

আপডেট: ক্লিঙ্কটির সমস্যা সমাধানের জন্য: ক) উপরে বর্ণিত টেকলাস্ট () পদ্ধতিটি ব্যবহার করা সমস্যার সমাধান করে, তবে আপনি যদি অতিরিক্ত পদ্ধতি ব্যতীত সত্যিই এটি করতে চান তবে আপনাকে কেবল এটি সনাক্ত করতে হবে যখন গণনার সময় হবে (বিপরীত () এক্সটেনশন পদ্ধতি হিসাবে ব্যবহার করা হয়, আপনার এটি সেভাবে ব্যবহার করার দরকার নেই:

List<string> mystring = new List<string>() { "one", "two", "three" }; 
mystring = Enumerable.Reverse(mystring).Take(2).Reverse().ToList();

List<string> mystring = new List<string>() { "one", "two", "three" }; mystring = mystring.Reverse().Take(2).Reverse(); আমার এটির যে সমস্যাটি রয়েছে তা যদি আমি বলি: আমি একটি সংকলক ত্রুটি পেয়েছি কারণ বিপরীত () বাতিল হয়ে যায় এবং সংকলক একটি লিনাকের পরিবর্তে সেই পদ্ধতিটি বেছে নেয় যা একটি আইমনামেবল ফিরিয়ে দেয়। পরামর্শ?
ক্লিনটন পিয়ার্স

1
আপনি স্পষ্টভাবে IEnumerable <স্ট্রিং> এ mystring কাস্ট করে এই সমস্যার সমাধান করতে পারে: ((IEnumerable <স্ট্রিং>) mystring) .Reverse () নিন (2) .Reverse ()।
জানুয়ারী Hettich

সহজ এবং যথেষ্ট সহজ তবে পুরোপুরি দুটি বার অর্ডারকে বিপরীত করা দরকার। এটি সর্বোত্তম উপায় হতে পারে
শাশ্বত

Kbrimington থেকে গৃহীত উত্তর ছাড়াও আমি এটি পছন্দ করি। শেষ Nরেকর্ড থাকার পরেও যদি আপনি অর্ডারটি যত্ন না করেন তবে আপনি দ্বিতীয়টি এড়িয়ে যেতে পারেন Reverse
জুলওয়ে

@ শাশ্বত এটি "সম্পূর্ণরূপে" দু'বার অর্ডারকে উল্টে দেয় না। দ্বিতীয় বিপরীতটি কেবল এন আইটেম সংগ্রহের ক্ষেত্রে প্রযোজ্য। তদ্ব্যতীত, বিপরীতে () কীভাবে এতে প্রথম কল প্রয়োগ করা হয় তা কেবল এন আইটেমগুলিকে বিপরীত করতে পারে। (। নেট 4.0 বাস্তবায়ন সংগ্রহটিকে একটি অ্যারেতে অনুলিপি করবে এবং এটি সূচকে পিছিয়ে যাবে)
জেমস কারান

47

দ্রষ্টব্য : আমি আপনার প্রশ্নের শিরোনাম মিস করেছি যা লিঙ্ক ব্যবহার করে বলেছিল তাই আমার উত্তর আসলে লিঙ্ক ব্যবহার করে না।

আপনি যদি পুরো সংগ্রহের একটি অলস অনুলিপিটি ক্যাচ করা এড়াতে চান তবে আপনি একটি সহজ পদ্ধতি লিখতে পারেন যা এটি লিঙ্কযুক্ত তালিকার সাহায্যে করে।

নিম্নলিখিত পদ্ধতিটি মূল সংগ্রহের সাথে পাওয়া প্রতিটি মানকে একটি লিঙ্কযুক্ত তালিকায় যুক্ত করবে এবং প্রয়োজনীয় আইটেমের সংখ্যায় লিঙ্কযুক্ত তালিকাটি ছাঁটাই করবে। যেহেতু এটি সংযোগের মাধ্যমে পুনরাবৃত্তির মাধ্যমে লিঙ্কযুক্ত তালিকাকে এই সংখ্যক আইটেমটিতে পুরো সময় ছাঁটাই করে রাখে, এটি কেবলমাত্র মূল সংগ্রহ থেকে সর্বাধিক এন আইটেমের অনুলিপি রাখবে।

এটির জন্য আপনাকে মূল সংগ্রহের আইটেমের সংখ্যা জানার প্রয়োজন হবে না বা এটির উপরে একবারে পুনরাবৃত্তি করতে হবে না।

ব্যবহার:

IEnumerable<int> sequence = Enumerable.Range(1, 10000);
IEnumerable<int> last10 = sequence.TakeLast(10);
...

সম্প্রসারণ পদ্ধতি:

public static class Extensions
{
    public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> collection,
        int n)
    {
        if (collection == null)
            throw new ArgumentNullException(nameof(collection));
        if (n < 0)
            throw new ArgumentOutOfRangeException(nameof(n), $"{nameof(n)} must be 0 or greater");

        LinkedList<T> temp = new LinkedList<T>();

        foreach (var value in collection)
        {
            temp.AddLast(value);
            if (temp.Count > n)
                temp.RemoveFirst();
        }

        return temp;
    }
}

আমি এখনও মনে করি প্রযুক্তিগতভাবে লিনক ব্যবহার না করা সত্ত্বেও আপনার কাছে একটি ভাল, বৈধ উত্তর আছে তবে আমি আপনাকে এখনও একটি +1 দিচ্ছি :)
ম্যাথিউ গ্রোভস

পরিষ্কার, ঝরঝরে এবং এক্সটেনসিবল +1!
ইয়াসের শায়খ

1
আমি মনে করি এটির একমাত্র সমাধান যা উত্সের গণককে দ্বিগুণ (বা আরও বেশি) চালিত করতে পারে না এবং গণনাটির বাস্তবায়ন জোর করে না, তাই বেশিরভাগ অ্যাপ্লিকেশনগুলিতে আমি বলব এটি শর্তে আরও কার্যকর হবে স্মৃতি এবং গতি।
স্প্রোটি

30

এখানে এমন একটি পদ্ধতি রয়েছে যা যে কোনও গণনার উপর কাজ করে তবে কেবল ও (এন) অস্থায়ী সঞ্চয়স্থান ব্যবহার করে:

public static class TakeLastExtension
{
    public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int takeCount)
    {
        if (source == null) { throw new ArgumentNullException("source"); }
        if (takeCount < 0) { throw new ArgumentOutOfRangeException("takeCount", "must not be negative"); }
        if (takeCount == 0) { yield break; }

        T[] result = new T[takeCount];
        int i = 0;

        int sourceCount = 0;
        foreach (T element in source)
        {
            result[i] = element;
            i = (i + 1) % takeCount;
            sourceCount++;
        }

        if (sourceCount < takeCount)
        {
            takeCount = sourceCount;
            i = 0;
        }

        for (int j = 0; j < takeCount; ++j)
        {
            yield return result[(i + j) % takeCount];
        }
    }
}

ব্যবহার:

List<int> l = new List<int> {4, 6, 3, 6, 2, 5, 7};
List<int> lastElements = l.TakeLast(3).ToList();

এটি উপাদানগুলির আকার হিসাবে রিং বাফার সাইজের এন ব্যবহার করে এটি পুরানো উপাদানগুলিকে নতুন দিয়ে ওভাররাইট করে। যখন গণনার শেষটি পৌঁছে যায় তখন রিং বাফারে সর্বশেষ এন উপাদান থাকে।


2
+1 টি এই খনি বেশি ভালো কার্য সম্পাদন থাকা উচিত, কিন্তু আপনি কি নিশ্চিতরূপে যখন সংগ্রহে কম উপাদানগুলি রয়েছে এটা ঠিক জিনিস আছে করা উচিত n
লাসে ভি কার্লসেন

ঠিক আছে, বেশিরভাগ সময় আমি ধরে নিই যে লোকেদের নিজেরাই এ জাতীয় জিনিস যুক্ত করার জন্য এসও থেকে কোড অনুলিপি করার সময় যত্ন নেবেন, সমস্যা হতে পারে না। আপনি যদি এটি যুক্ত করতে চলেছেন তবে নালার জন্য সংগ্রহের পরিবর্তনশীলও পরীক্ষা করে দেখুন। অন্যথায়, দুর্দান্ত সমাধান :) আমি নিজেই একটি রিং-বাফার ব্যবহারের বিষয়ে বিবেচনা করছিলাম, কারণ একটি লিঙ্কযুক্ত তালিকাটি জিসি-চাপকে যুক্ত করবে, তবে কিছুক্ষণ হয়েছে যখন আমি একটি করেছি এবং পরীক্ষার কোড নিয়ে আমি ঝামেলা করতে চাইনি যদি আমি এটি সঠিকভাবে করেন। আমি অবশ্যই বলব যে আমি লিনকিপ্যাডের সাথে প্রেমে পড়ছি :) লিনকপ্যাড.এন.এ
লাসে ভি। কার্লসেন

2
সম্ভাব্য অপ্টিমাইজেশন হ'ল প্রচুর পরিমাণে আইলিস্ট প্রয়োগ করা হয়েছে কিনা তা যাচাই করা এবং যদি এটি হয় তুচ্ছ সমাধান ব্যবহার করুন use অস্থায়ী স্টোরেজ পদ্ধতির কেবল তখনই যথাযথভাবে 'স্ট্রিমিং' আইনিউবারেবলস
পায়ার্স 7

1
তুচ্ছ নাইট-পিক: আপনার যুক্তি
আউটআউটরেঞ্জইপশন সম্পর্কে

28

.NET কোর 2.0+ লাইনকিউ পদ্ধতি সরবরাহ করে TakeLast() :

https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.takelast

উদাহরণ :

Enumerable
    .Range(1, 10)
    .TakeLast(3) // <--- takes last 3 items
    .ToList()
    .ForEach(i => System.Console.WriteLine(i))

// outputs:
// 8
// 9
// 10

আমি ব্যবহার করছি: নেট স্ট্যান্ডার্ড 2.0 এবং আমার কাছে এটি উপলব্ধ নেই। কোনো সমস্যা? :(
সুপারজেএমএন

@ সুপারজেএমএন যদিও আপনি। নেট স্ট্যান্ডার্ড 2.0 গ্রন্থাগারগুলি উল্লেখ করছেন তবে আপনি আপনার প্রকল্পে ডটনেট কোরের সঠিক সংস্করণটিকে লক্ষ্য করছেন না। এই পদ্ধতিটি v1.x ( netcoreapp1.x) এর জন্য উপলভ্য নয় তবে কেবল ডটনেটकोर ( ) এর v2.0 এবং v2.1 এর জন্য netcoreapp2.x। এটি সম্ভবত আপনি পুরো কাঠামোটিকে লক্ষ্য করে তৈরি করতে পারেন (উদাঃ net472) যা অসমর্থিত। (.net মান লিব উপরের কোনও দ্বারা ব্যবহার করা যাবে কিন্তু শুধুমাত্র একটি টার্গেট ফ্রেমওয়ার্ক নির্দিষ্ট API গুলি নির্দিষ্ট প্রকাশ করতে পারে দেখুন। docs.microsoft.com/en-us/dotnet/standard/frameworks )
সত্যজিৎ

1
এগুলি এখন আরও বেশি হওয়া দরকার। চাকাটি পুনরায় উদ্ভাবনের দরকার নেই
জেমস উডলি

11

আমি অবাক হয়েছি যে এটির কথা কেউ উল্লেখ করেনি, তবে স্কিপহিলের এমন একটি পদ্ধতি রয়েছে যা উপাদানটির সূচক ব্যবহার করে

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

    int goldenIndex = source.Count() - n;
    return source.SkipWhile((val, index) => index < goldenIndex);
}

//Or if you like them one-liners (in the spirit of the current accepted answer);
//However, this is most likely impractical due to the repeated calculations
collection.SkipWhile((val, index) => index < collection.Count() - N)

এই সমাধানটি অন্যদের কাছে উপস্থাপিত হওয়ার একমাত্র উপকারটি হ'ল আপনার দু'বার পৃথক ক্রিয়াকলাপের পরিবর্তে আরও শক্তিশালী এবং দক্ষ লাইনকিউ ক্যোয়ারী তৈরি করার জন্য প্রিকিকেট যুক্ত করার বিকল্প থাকতে পারে IE

public static IEnumerable<T> FilterLastN<T>(this IEnumerable<T> source, int n, Predicate<T> pred)
{
    int goldenIndex = source.Count() - n;
    return source.SkipWhile((val, index) => index < goldenIndex && pred(val));
}

9

আরএক্স এর সিস্টেমে এনিউমারেবলএক্স.টেকলাস্ট ব্যবহার করুন n ইন্টারেক্টিভ সমাবেশে। এটি @ মার্কের মতো একটি ও (এন) বাস্তবায়ন, তবে এটি রিং-বাফার কনস্ট্রাক্টের পরিবর্তে একটি সারি ব্যবহার করে (এবং যখন এটি বাফার সক্ষমতাতে পৌঁছায় আইটেমগুলির সন্ধান করে)।

(এনবি: এটি আইনিউমারেবল সংস্করণ - আইওজার্ভেবল সংস্করণ নয়, যদিও দুটিটির বাস্তবায়ন বেশ অভিন্ন)


এটি সেরা উত্তর। কোনও উপযুক্ত লাইব্রেরি রয়েছে যা কাজ করে এবং আরএক্স দল উচ্চমানের হলে আপনার নিজের রোল করবেন না।
ব্র্যাডগোনসার্ফিং

আপনি যদি এটির সাথে যাচ্ছেন তবে নুগেট - nuget.org/packages/Ix-Ancnc
nikib3ro

বিজ্ঞপ্তি বাফারQueue<T> ব্যবহার করে কি সি # কার্যকর করা হচ্ছে না ?
টাইগ্রু

@ টিগ্রো। না, এটি বিজ্ঞপ্তি নয়
সিটিকিড


6

আপনি যদি কোনও কী (যেমন একটি ডাটাবেস থেকে প্রবেশকারীর জন্য) সাথে কোনও সংগ্রহের কাজ করছেন তবে দ্রুত (অর্থাত্ নির্বাচিত উত্তরের চেয়ে দ্রুত) সমাধানটি হবে

collection.OrderByDescending(c => c.Key).Take(3).OrderBy(c => c.Key);

+1 আমার পক্ষে কাজ করে এবং এটি পড়তে সহজ, আমার তালিকায় আমার কাছে কয়েকটি সংখ্যক অবজেক্ট রয়েছে
fubo

5

আপনি যদি মোনাডের অংশ হিসাবে আরএক্সে ডুবতে আপত্তি করেন না তবে আপনি ব্যবহার করতে পারেন TakeLast:

IEnumerable<int> source = Enumerable.Range(1, 10000);

IEnumerable<int> lastThree = source.AsObservable().TakeLast(3).AsEnumerable();

2
আপনি AsObservable () প্রয়োজন হবে না যদি তোমরা হয়েছে RX এর System.Interactive রেফারেন্স System.Reactive পরিবর্তে (আমার উত্তর দেখুন)
piers7

2

যদি কোনও তৃতীয় পক্ষের লাইব্রেরি ব্যবহার করা একটি বিকল্প হয়, মোরলিংক সংজ্ঞা দেয় TakeLast()যা ঠিক এটি করে does


2

আমি দক্ষতা এবং সরলতা একত্রিত করার চেষ্টা করেছি এবং এটি দিয়ে শেষ করব:

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

    Queue<T> lastElements = new Queue<T>();
    foreach (T element in source)
    {
        lastElements.Enqueue(element);
        if (lastElements.Count > count)
        {
            lastElements.Dequeue();
        }
    }

    return lastElements;
}

কর্মক্ষমতা সম্পর্কে: সি # তে, Queue<T>একটি বিজ্ঞপ্তি বাফার ব্যবহার করে প্রয়োগ করা হয় যাতে প্রতিটি লুপের কোনও বস্তু ইনস্ট্যান্টেশন হয় না (কেবল যখন সারিটি বড় হয় তখন)। আমি সারি সক্ষমতা সেট করিনি (ডেডিকেটেড কনস্ট্রাক্টর ব্যবহার করে) কারণ কেউ এই এক্সটেনশানটির সাথে কল করতে পারে count = int.MaxValue। অতিরিক্ত পারফরম্যান্সের জন্য আপনি উত্সটি প্রয়োগ করে IList<T>কিনা এবং যদি হ্যাঁ, সরাসরি অ্যারে সূচকগুলি ব্যবহার করে শেষ মানগুলি বের করে নিতে পারেন কিনা তা পরীক্ষা করতে পারেন ।


1

লিনকিউ ব্যবহার করে কোনও সংগ্রহের শেষ এন নেওয়া সামান্য অক্ষম কারণ উপরের সমস্ত সমাধানের জন্য সংগ্রহটি জুড়ে পুনরুক্তি প্রয়োজন। TakeLast(int n)ভিতরেSystem.Interactive এই সমস্যা হয়েছে।

আপনার যদি একটি তালিকা থাকে তবে আরও কার্যকর জিনিসটি নিম্নলিখিত পদ্ধতিটি ব্যবহার করে এটি কেটে ফেলা হয়

/// Select from start to end exclusive of end using the same semantics
/// as python slice.
/// <param name="list"> the list to slice</param>
/// <param name="start">The starting index</param>
/// <param name="end">The ending index. The result does not include this index</param>
public static List<T> Slice<T>
(this IReadOnlyList<T> list, int start, int? end = null)
{
    if (end == null)
    {
        end = list.Count();
    }
     if (start < 0)
    {
        start = list.Count + start;
    }
     if (start >= 0 && end.Value > 0 && end.Value > start)
    {
        return list.GetRange(start, end.Value - start);
    }
     if (end < 0)
    {
        return list.GetRange(start, (list.Count() + end.Value) - start);
    }
     if (end == start)
    {
        return new List<T>();
    }
     throw new IndexOutOfRangeException(
        "count = " + list.Count() + 
        " start = " + start +
        " end = " + end);
}

সঙ্গে

public static List<T> GetRange<T>( this IReadOnlyList<T> list, int index, int count )
{
    List<T> r = new List<T>(count);
    for ( int i = 0; i < count; i++ )
    {
        int j=i + index;
        if ( j >= list.Count )
        {
            break;
        }
        r.Add(list[j]);
    }
    return r;
}

এবং কিছু পরীক্ষার কেস

[Fact]
public void GetRange()
{
    IReadOnlyList<int> l = new List<int>() { 0, 10, 20, 30, 40, 50, 60 };
     l
        .GetRange(2, 3)
        .ShouldAllBeEquivalentTo(new[] { 20, 30, 40 });
     l
        .GetRange(5, 10)
        .ShouldAllBeEquivalentTo(new[] { 50, 60 });

}
 [Fact]
void SliceMethodShouldWork()
{
    var list = new List<int>() { 1, 3, 5, 7, 9, 11 };
    list.Slice(1, 4).ShouldBeEquivalentTo(new[] { 3, 5, 7 });
    list.Slice(1, -2).ShouldBeEquivalentTo(new[] { 3, 5, 7 });
    list.Slice(1, null).ShouldBeEquivalentTo(new[] { 3, 5, 7, 9, 11 });
    list.Slice(-2)
        .Should()
        .BeEquivalentTo(new[] {9, 11});
     list.Slice(-2,-1 )
        .Should()
        .BeEquivalentTo(new[] {9});
}

1

আমি জানি এই প্রশ্নের উত্তর দিতে দেরি হয়েছে। তবে আপনি যদি আইলিস্ট <> প্রকারের সংগ্রহের সাথে কাজ করছেন এবং আপনি ফিরে আসা সংগ্রহের আদেশের বিষয়ে চিন্তা করছেন না, তবে এই পদ্ধতিটি দ্রুত কাজ করছে। আমি মার্ক বাইয়ার্স উত্তরটি ব্যবহার করেছি এবং কিছুটা পরিবর্তন করেছি। সুতরাং এখন টেকলাস্ট পদ্ধতিটি হ'ল:

public static IEnumerable<T> TakeLast<T>(IList<T> source, int takeCount)
{
    if (source == null) { throw new ArgumentNullException("source"); }
    if (takeCount < 0) { throw new ArgumentOutOfRangeException("takeCount", "must not be negative"); }
    if (takeCount == 0) { yield break; }

    if (source.Count > takeCount)
    {
        for (int z = source.Count - 1; takeCount > 0; z--)
        {
            takeCount--;
            yield return source[z];
        }
    }
    else
    {
        for(int i = 0; i < source.Count; i++)
        {
            yield return source[i];
        }
    }
}

পরীক্ষার জন্য আমি মার্ক বাইয়ার্স পদ্ধতি এবং কেব্রিমিংটনের অ্যান্ডসওয়ার ব্যবহার করেছি । এটি পরীক্ষা:

IList<int> test = new List<int>();
for(int i = 0; i<1000000; i++)
{
    test.Add(i);
}

Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();

IList<int> result = TakeLast(test, 10).ToList();

stopwatch.Stop();

Stopwatch stopwatch1 = new Stopwatch();
stopwatch1.Start();

IList<int> result1 = TakeLast2(test, 10).ToList();

stopwatch1.Stop();

Stopwatch stopwatch2 = new Stopwatch();
stopwatch2.Start();

IList<int> result2 = test.Skip(Math.Max(0, test.Count - 10)).Take(10).ToList();

stopwatch2.Stop();

এবং এখানে 10 টি উপাদান নেওয়ার ফলাফল রয়েছে:

এখানে চিত্র বর্ণনা লিখুন

এবং 1000001 উপাদান নেওয়ার জন্য ফলাফলগুলি: এখানে চিত্র বর্ণনা লিখুন


1

এখানে আমার সমাধান:

public static class EnumerationExtensions
{
    public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> input, int count)
    {
        if (count <= 0)
            yield break;

        var inputList = input as IList<T>;

        if (inputList != null)
        {
            int last = inputList.Count;
            int first = last - count;

            if (first < 0)
                first = 0;

            for (int i = first; i < last; i++)
                yield return inputList[i];
        }
        else
        {
            // Use a ring buffer. We have to enumerate the input, and we don't know in advance how many elements it will contain.
            T[] buffer = new T[count];

            int index = 0;

            count = 0;

            foreach (T item in input)
            {
                buffer[index] = item;

                index = (index + 1) % buffer.Length;
                count++;
            }

            // The index variable now points at the next buffer entry that would be filled. If the buffer isn't completely
            // full, then there are 'count' elements preceding index. If the buffer *is* full, then index is pointing at
            // the oldest entry, which is the first one to return.
            //
            // If the buffer isn't full, which means that the enumeration has fewer than 'count' elements, we'll fix up
            // 'index' to point at the first entry to return. That's easy to do; if the buffer isn't full, then the oldest
            // entry is the first one. :-)
            //
            // We'll also set 'count' to the number of elements to be returned. It only needs adjustment if we've wrapped
            // past the end of the buffer and have enumerated more than the original count value.

            if (count < buffer.Length)
                index = 0;
            else
                count = buffer.Length;

            // Return the values in the correct order.
            while (count > 0)
            {
                yield return buffer[index];

                index = (index + 1) % buffer.Length;
                count--;
            }
        }
    }

    public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> input, int count)
    {
        if (count <= 0)
            return input;
        else
            return input.SkipLastIter(count);
    }

    private static IEnumerable<T> SkipLastIter<T>(this IEnumerable<T> input, int count)
    {
        var inputList = input as IList<T>;

        if (inputList != null)
        {
            int first = 0;
            int last = inputList.Count - count;

            if (last < 0)
                last = 0;

            for (int i = first; i < last; i++)
                yield return inputList[i];
        }
        else
        {
            // Aim to leave 'count' items in the queue. If the input has fewer than 'count'
            // items, then the queue won't ever fill and we return nothing.

            Queue<T> elements = new Queue<T>();

            foreach (T item in input)
            {
                elements.Enqueue(item);

                if (elements.Count > count)
                    yield return elements.Dequeue();
            }
        }
    }
}

কোডটি কিছুটা চঞ্চল, তবে একটি ড্রপ-ইন পুনঃব্যবহারযোগ্য উপাদান হিসাবে, এটি বেশিরভাগ পরিস্থিতিতে এটির পাশাপাশি সঞ্চালন করা উচিত এবং এটি কোডটি এটি সুন্দর এবং সংক্ষিপ্তভাবে ব্যবহার করবে using :-)

আমার TakeLastজন্যIList`1 একইটি রিং বাফার অ্যালগরিদমের উপর ভিত্তি করে তৈরি করা হয়েছে যা উত্তরগুলি @ মার্ক মার্ক এবং @ ম্যাকিচ্যান আরও উত্তর দিয়েছেন। এটি আকর্ষণীয় যে তারা কতটা অনুরূপ - আমি সম্পূর্ণ স্বাধীনভাবে লিখেছি। অনুমান করুন সঠিকভাবে রিং বাফার করার কেবলমাত্র একটি উপায় আছে। :-)

@ কেব্রিমিংটনের উত্তরটির দিকে তাকিয়ে, IQuerable<T>সত্তা ফ্রেমওয়ার্কের সাথে ভালভাবে কাজ করা পদ্ধতির দিকে ফিরে যাওয়ার জন্য এটিতে আরও একটি অতিরিক্ত চেক যুক্ত করা যেতে পারে - ধরে নিই যে এই মুহুর্তে আমার যা আছে তা তা নয়।


0

সংগ্রহের (অ্যারে) থেকে শেষ 3 টি উপাদান কীভাবে নেওয়া যায় তার বাস্তব উদাহরণের নীচে:

// split address by spaces into array
string[] adrParts = adr.Split(new string[] { " " },StringSplitOptions.RemoveEmptyEntries);
// take only 3 last items in array
adrParts = adrParts.SkipWhile((value, index) => { return adrParts.Length - index > 3; }).ToArray();

0

ত্রুটি ছাড়াই সমস্ত ব্যাপ্তি পেতে এই পদ্ধতিটি ব্যবহার করা

 public List<T> GetTsRate( List<T> AllT,int Index,int Count)
        {
            List<T> Ts = null;
            try
            {
                Ts = AllT.ToList().GetRange(Index, Count);
            }
            catch (Exception ex)
            {
                Ts = AllT.Skip(Index).ToList();
            }
            return Ts ;
        }

0

বিজ্ঞপ্তি বাফার ব্যবহারের সাথে সামান্য ভিন্ন বাস্তবায়ন। Benchmarks দেখায় যে পদ্ধতি প্রায় দুই বার ব্যবহার বেশী চেয়ে দ্রুত সারি (বাস্তবায়নের TakeLast মধ্যে System.Linq ,) তবে একটা খরচ ছাড়া - এটা একটি বাফার যা উপাদানের অনুরোধ সংখ্যা সহ বৃদ্ধি প্রয়োজন, এমনকি যদি আপনি একটি আছে ছোট সংগ্রহ আপনি বিশাল মেমরি বরাদ্দ পেতে পারেন।

public IEnumerable<T> TakeLast<T>(IEnumerable<T> source, int count)
{
    int i = 0;

    if (count < 1)
        yield break;

    if (source is IList<T> listSource)
    {
        if (listSource.Count < 1)
            yield break;

        for (i = listSource.Count < count ? 0 : listSource.Count - count; i < listSource.Count; i++)
            yield return listSource[i];

    }
    else
    {
        bool move = true;
        bool filled = false;
        T[] result = new T[count];

        using (var enumerator = source.GetEnumerator())
            while (move)
            {
                for (i = 0; (move = enumerator.MoveNext()) && i < count; i++)
                    result[i] = enumerator.Current;

                filled |= move;
            }

        if (filled)
            for (int j = i; j < count; j++)
                yield return result[j];

        for (int j = 0; j < i; j++)
            yield return result[j];

    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.