কোনও আইনিউমারেবলের মধ্যে কোনও উপাদানটির সূচক কীভাবে পাবেন?


144

আমি এটি লিখেছি:

public static class EnumerableExtensions
{
    public static int IndexOf<T>(this IEnumerable<T> obj, T value)
    {
        return obj
            .Select((a, i) => (a.Equals(value)) ? i : -1)
            .Max();
    }

    public static int IndexOf<T>(this IEnumerable<T> obj, T value
           , IEqualityComparer<T> comparer)
    {
        return obj
            .Select((a, i) => (comparer.Equals(a, value)) ? i : -1)
            .Max();
    }
}

তবে আমি জানি না এটি ইতিমধ্যে বিদ্যমান আছে কি না?


4
একটি Maxপদ্ধতির সাথে সমস্যাটি হ'ল: এটি সন্ধান করে এবং খ: ডুপ্লিকেটগুলি উপস্থিত থাকলে এটি সর্বশেষ সূচকটি ফেরত দেয় (লোকেরা সাধারণত প্রথম সূচকের প্রত্যাশা করে)
মার্ক গ্রাভেল

1
geewwithblogs.net 4 টি সমাধান এবং তাদের কার্য সম্পাদনের তুলনা করে। ToList()/FindIndex()কৌতুক সঞ্চালিত সেরা
nixda

উত্তর:


51

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


8
বর্তমানে আমি এই থ্রেডটি পেরিয়ে এসেছি কারণ তৃতীয় পক্ষের উপাদানগুলির সাথে আমার আইএননামেবল <> অবজেক্টগুলিকে আইলিস্ট টাইপের ডেটাসোর্সাকে সমর্থন করার জন্য আইইনিউরেবল <> টাইপের জন্য জেনেরিক আইলিস্ট <> র‌্যাপার প্রয়োগ করছি। আমি সম্মত হই যে একটি আইনুমেবল অবজেক্টের মধ্যে কোনও উপাদানটির একটি সূচক আনার চেষ্টা করা সম্ভবত বেশিরভাগ ক্ষেত্রেই ভুল কিছু করা হয়েছে এমন চিহ্নের চিহ্ন সম্ভবত এমন সূচকগুলি খুঁজে পাওয়া যায় যখন একবার সূচকগুলি সন্ধানের জন্য স্মৃতিতে একটি বৃহত সংগ্রহকে পুনরুত্পাদন করে index আপনার যদি ইতিমধ্যে একটি অনুমিত হয় তখন একটি একক উপাদান of
jpierson

215
-1 কারণ: আপনি ক এর বাইরে সূচক পেতে চাওয়ার বৈধ কারণ রয়েছে IEnumerable<>। গোটা "আপনি এই কাজটি করতে চাইবেন" ডগমা কিনে নেই।
জন আলেক্সিউ

78
@ Ja72 এর সাথে সম্মত হন; যদি আপনার সাথে সূচকের সাথে ডিল করা না থাকে IEnumerableতবে Enumerable.ElementAtএটি উপস্থিত থাকবে না। IndexOfকেবল বিপরীত - এটির বিরুদ্ধে যে কোনও যুক্তি অবশ্যই সমানভাবে প্রযোজ্য ElementAt
ওল

7
ক্লিয়ারি, সি # IIndexableEnumerable ধারণাটি মিস করে। এটি কেবলমাত্র সি ++ এসটিএল পরিভাষায় একটি "এলোমেলো প্রবেশযোগ্য" ধারণার সমতুল্য।
v.oddou

14
ওভারলোডের সাথে এক্সটেনশনগুলির মতো নির্বাচন ((x, i) => ...) বোঝায় যে এই সূচিগুলি থাকা উচিত
মাইকেল

126

আমি বুদ্ধি প্রশ্ন করতে চাই, কিন্তু সম্ভবত:

source.TakeWhile(x => x != value).Count();

( প্রয়োজনে EqualityComparer<T>.Defaultঅনুকরণ করার জন্য ব্যবহার করে !=) - তবে আপনাকে যদি খুঁজে না পাওয়া যায় তবে ফিরে আসতে হবে -১ দেখতে পাওয়া যায় ... তাই সম্ভবত এটি দীর্ঘ পথ থেকে করুন

public static int IndexOf<T>(this IEnumerable<T> source, T value)
{
    int index = 0;
    var comparer = EqualityComparer<T>.Default; // or pass in as a parameter
    foreach (T item in source)
    {
        if (comparer.Equals(item, value)) return index;
        index++;
    }
    return -1;
}

8
"প্রজ্ঞাকে প্রশ্নবিদ্ধ করার" জন্য +1। 10 এর মধ্যে 9 বার এটি সম্ভবত প্রথম স্থানে একটি খারাপ ধারণা।
জোয়েল কোহোর্ন 21

সুস্পষ্ট লুপ সমাধানটিও সিলেক্ট ()। সর্বোচ্চ () সমাধানের চেয়ে 2x দ্রুত (সবচেয়ে খারাপ ক্ষেত্রে) চালায় runs
স্টিভ গুইদি

1
আপনি টেকহাইল ছাড়াই ল্যাম্বদা দ্বারা উপাদানগুলি গণনা করতে পারেন - এটি একটি লুপ সংরক্ষণ করে: উত্স.কাউন্ট (x => এক্স! = মান);
কামারে

10
@ কামারে - না, এটি কিছু আলাদা করে। ব্যর্থতা পেলে টেকহাইল থামে ; মেলে (গণনা করা) মেলে এমনগুলি প্রদান করে। অর্থাত্ যদি প্রথমটি মিস হয় এবং সমস্ত কিছু সত্য হয় তবে টেকহাইল (পূর্ব) C হিসাব () 0 প্রতিবেদন করবে; গণনা (পূর্ব) এন -1 প্রতিবেদন করবে।
মার্ক গ্র্যাভেল

1
TakeWhileচালাক! মনে রাখবেন যদিও এই Countউপাদানটি উপস্থিত না থাকলে এটি ফিরে আসে যা মানক আচরণ থেকে বিচ্যুতি।
নওফাল

27

আমি এটি এর মতো বাস্তবায়ন করব:

public static class EnumerableExtensions
{
    public static int IndexOf<T>(this IEnumerable<T> obj, T value)
    {
        return obj.IndexOf(value, null);
    }

    public static int IndexOf<T>(this IEnumerable<T> obj, T value, IEqualityComparer<T> comparer)
    {
        comparer = comparer ?? EqualityComparer<T>.Default;
        var found = obj
            .Select((a, i) => new { a, i })
            .FirstOrDefault(x => comparer.Equals(x.a, value));
        return found == null ? -1 : found.i;
    }
}

1
এটি আসলে খুব সুন্দর, +1! এটি অতিরিক্ত অবজেক্টগুলিকে জড়িত, তবে সেগুলি তুলনামূলকভাবে সস্তা (GEN0) হওয়া উচিত , সুতরাং বিশাল সমস্যা নয়। ==কাজ প্রয়োজন হতে পারে?
মার্ক গ্র্যাভেল

1
প্রকৃত লিনকিউ স্টাইলে আইকোয়ালিটি কম্পিউটারের ওভারলোড যুক্ত করা হয়েছে। ;)
dahlbyk

1
আমার মনে হয় আপনি বলতে চাইছেন ... তুলনামূলক.একুয়ালস (এক্সএ, মান) =)
মার্চ

যেহেতু সিলেক্ট এক্সপ্রেশনটি সম্মিলিত ফলাফলটি প্রত্যাবর্তন করে, যা পরে প্রক্রিয়া করা হয়, আমি কল্পনা করেছিলাম কীভ্যালিউপায়ার মান প্রকারটি আপনাকে স্পষ্টভাবে কোনও ধরণের হিপ বরাদ্দ এড়াতে অনুমতি দেবে, যতক্ষণ না .NET ইমপ্ল্যাক স্ট্যাকের উপর মান প্রকারগুলি বরাদ্দ করে এবং যে কোনও রাষ্ট্রীয় মেশিন লিনকিউ জেনারেট করে সেলেক্ট রেজাল্টের জন্য এমন একটি ক্ষেত্র ব্যবহার করে যা বেয়ার অবজেক্ট হিসাবে ঘোষিত হয়নি (সুতরাং কেভিপি ফলাফলকে বক্স করে দেবে)। অবশ্যই, আপনাকে পাওয়া == নাল অবস্থার পুনরায় কাজ করতে হবে (যেহেতু এটি এখন কেভিপি মান হতে পারে)। হতে পারে KVP<T, int?>
DefaultIfEmpty

1
সুন্দর বাস্তবায়ন, যদিও আমি যুক্ত করার পরামর্শ দিচ্ছি তা হ'ল এটি যাচাই করা উচিত যা কিনা আপত্তিটি প্রয়োগ করে IList<T>এবং যদি তা হয় তবে তার সূচিপত্র পদ্ধতিটি যদি নির্দিষ্ট ধরণের নির্দিষ্ট অপ্টিমাইজেশন থাকে তবে তা পিছিয়ে দিন।
জোশ

16

আমি বর্তমানে যেভাবে এটি করছি তা ইতিমধ্যে প্রস্তাবিতগুলির চেয়ে কিছুটা ছোট এবং যতদূর আমি বলতে পারি পছন্দসই ফলাফলটি দেয়:

 var index = haystack.ToList().IndexOf(needle);

এটি কিছুটা আড়ষ্ট, তবে এটি কাজটি করে এবং মোটামুটি সংক্ষিপ্ত।


6
যদিও এটি ছোট সংগ্রহের জন্য কাজ করবে, ধরুন আপনার "খড়ের খালি" -এ মিলিয়ন আইটেম রয়েছে। এটিতে টোললিস্ট () করা সমস্ত দশ মিলিয়ন উপাদানকে পুনরাবৃত্তি করবে এবং সেগুলি একটি তালিকায় যুক্ত করবে। তারপরে এটি তালিকার মাধ্যমে মিলবে উপাদানগুলির সূচকটি অনুসন্ধান করবে। এটি চূড়ান্তভাবে অদক্ষ এবং সেইসাথে তালিকাটি বড় হয়ে গেলে একটি ব্যতিক্রম ছুঁড়ে ফেলার সম্ভাবনাও থাকবে।
esteuart

3
@ এসটিয়ার্ট অবশ্যই - আপনার ব্যবহারের ক্ষেত্রে উপযুক্ত একটি পদ্ধতির চয়ন করতে হবে। আমার সন্দেহ আছে যে একটি আকারের সমস্ত সমাধান ফিট করে, মূল কারণগুলি কেন গ্রন্থাগারগুলিতে বাস্তবায়ন হয় না।
মার্ক ওয়াটস

8

অবস্থানটি ধরার সর্বোত্তম উপায়টি হ'ল FindIndexএই ফাংশনটি কেবলমাত্র জন্য উপলব্ধList<>

উদাহরণ

int id = listMyObject.FindIndex(x => x.Id == 15); 

আপনার যদি গণক বা অ্যারে থাকে তবে এইভাবে ব্যবহার করুন

int id = myEnumerator.ToList().FindIndex(x => x.Id == 15); 

অথবা

 int id = myArray.ToList().FindIndex(x => x.Id == 15); 

7

আমি মনে করি সর্বোত্তম বিকল্পটি এটির মতো বাস্তবায়ন করা:

public static int IndexOf<T>(this IEnumerable<T> enumerable, T element, IEqualityComparer<T> comparer = null)
{
    int i = 0;
    comparer = comparer ?? EqualityComparer<T>.Default;
    foreach (var currentElement in enumerable)
    {
        if (comparer.Equals(currentElement, element))
        {
            return i;
        }

        i++;
    }

    return -1;
}

এটি বেনামে অবজেক্টও তৈরি করবে না


5

খেলায় কিছুটা দেরি হয়েছে, আমি জানি ... তবে আমি সম্প্রতি এটি করেছি। এটি আপনার চেয়ে কিছুটা পৃথক, তবে প্রোগ্রামারকে সাম্যতা ক্রিয়াকলাপটি কী হবে তা নির্ধারণ করতে দেয় (ভবিষ্যদ্বাণী)। যা আমি বিভিন্ন ধরণের সাথে ডিল করার সময় খুব দরকারী বলে মনে করি, যেহেতু আমার তখন অবজেক্ট টাইপ নির্বিশেষে <T>এবং সাম্যতা অপারেটরে অন্তর্নির্মিত এটি করার একটি সাধারণ উপায় রয়েছে ।

এটির একটি খুব ছোট স্মৃতি মেমরির পদচিহ্নও রয়েছে এবং খুব, খুব দ্রুত / দক্ষ ... যদি আপনি এটি যত্নবান হন।

আরও খারাপ, আপনি এটি কেবলমাত্র আপনার এক্সটেনশনের তালিকায় যুক্ত করবেন।

যাইহোক ... এখানে।

 public static int IndexOf<T>(this IEnumerable<T> source, Func<T, bool> predicate)
 {
     int retval = -1;
     var enumerator = source.GetEnumerator();

     while (enumerator.MoveNext())
     {
         retval += 1;
         if (predicate(enumerator.Current))
         {
             IDisposable disposable = enumerator as System.IDisposable;
             if (disposable != null) disposable.Dispose();
             return retval;
         }
     }
     IDisposable disposable = enumerator as System.IDisposable;
     if (disposable != null) disposable.Dispose();
     return -1;
 }

আশা করি এটি কাউকে সাহায্য করবে।


1
হতে পারে আমি কিছু মিস করছি, তবে কেন GetEnumeratorএবং কেবল MoveNextএকটিটির চেয়ে কেন foreach?
জোশ গালাগের

1
সংক্ষিপ্ত উত্তর? দক্ষতা. লং উত্তর: msdn.microsoft.com/en-us/library/9yb8xew9.aspx
MaxOvrdrv

2
আইএলটির দিকে তাকালে এটি প্রদর্শিত হয় যে পারফরম্যান্সের পার্থক্যটি হ'ল এটি যদি প্রয়োগ করে তবে একটি গণককে foreachকল করবে । ( স্ট্যাকওভারফ্লো.com/ প্রশ্নগুলি / 8৪৮২৩৯9 / দেখুন দেখুন ) এই উত্তরের কোডটি যেমন জানে না যে কল করার ফলাফলটি ডিসপোজেবল হয় কি না এটি একইভাবে করা উচিত। এই মুহুর্তে আমি এখনও অস্পষ্ট যে একটি উপযুক্ত সুবিধা আছে, যদিও কিছু অতিরিক্ত আইএল ছিল যার উদ্দেশ্য আমার দিকে ঝাঁপিয়ে পড়েনি! DisposeIDisposableGetEnumerator
জোশ গালাগের

@ জোশগাল্লাগর পূর্ববর্তী ভবিষ্যদ্বাণী এবং (i) এর মধ্যে পারফেক্ট সুবিধাগুলি সম্পর্কে কিছুক্ষণ আগে আমি কিছুটা গবেষণা করেছি এবং (i) ব্যবহারের মূল সুবিধাটি হ'ল এটি পুনরায় তৈরি / পাস করার পরিবর্তে বস্তুটিকে বাই-রাইফস করে দেয় ফিরে বাইওয়াল। আমি ধরে নিলাম মুভনেক্সট বনাম পূর্বাভাসের ক্ষেত্রেও এটি একই প্রযোজ্য, তবে আমি সে সম্পর্কে নিশ্চিত নই। হতে পারে তারা দুজনই
বাইওয়াল

2
এই ব্লগটি পড়ার ( ব্লগস.এমএসএনএন বিবি / এরিক্লিপার্ট / অর্চিভ / ২০০০/০৯/৩০/২ ) হতে পারে যে " ইটারেটর লুপ" তিনি উল্লেখ করছেন এটি একটি foreachলুপ, কোন ক্ষেত্রে বিশেষ ক্ষেত্রে Tমান ধরণের হওয়ার কারণে এটি লুপটি ব্যবহার করে কোনও বাক্স / আনবক্স অপারেশন সংরক্ষণ করতে পারে। যাইহোক, এটি আপনার উত্তরটির একটি সংস্করণ থেকে আমি পেয়েছি আইএল দ্বারা বহন করা হয় না foreach। যদিও আমি এখনও মনে করি যে পুনরাবৃত্তির শর্তসাপেক্ষ নিষ্পত্তি গুরুত্বপূর্ণ। এটি অন্তর্ভুক্ত করার জন্য আপনি উত্তরটি সংশোধন করতে পারেন?
জোশ গ্যালা’র

5

কয়েক বছর পরে, তবে এটি লিনক ব্যবহার করে, যদি না পাওয়া যায় তবে -1 ফেরত দেয়, অতিরিক্ত বস্তু তৈরি করে না এবং খুঁজে পাওয়া গেলে শর্ট সার্কিট করা উচিত [পুরো আইএনওমারেবলের সাথে পুনরাবৃত্তি করার বিপরীতে]:

public static int IndexOf<T>(this IEnumerable<T> list, T item)
{
    return list.Select((x, index) => EqualityComparer<T>.Default.Equals(item, x)
                                     ? index
                                     : -1)
               .FirstOr(x => x != -1, -1);
}

যেখানে 'ফার্স্টঅর' রয়েছে:

public static T FirstOr<T>(this IEnumerable<T> source, T alternate)
{
    return source.DefaultIfEmpty(alternate)
                 .First();
}

public static T FirstOr<T>(this IEnumerable<T> source, Func<T, bool> predicate, T alternate)
{
    return source.Where(predicate)
                 .FirstOr(alternate);
}

এটি করার আর একটি উপায় হ'ল: পাবলিক স্ট্যাটিক ইনডেক্স <ট> (এই আইনিম্যুয়াল <T> তালিকা, টি আইটেম) {ইন্টি = তালিকাগুলি e আইটেম, এক্স)? x + 1: -1)। প্রথম অরডিফল্ট (x => x> 0); ফিরে (ই == 0)? -1: ই - 1); }
অনু থমাস চান্দি

"অতিরিক্ত বস্তু তৈরি করে না"। লিনক আসলে পটভূমিতে অবজেক্ট তৈরি করবে যাতে এটি পুরোপুরি সঠিক নয়। উভয় source.Whereএবং source.DefaultIfEmptyউদাহরণস্বরূপ IEnumerableপ্রতিটি তৈরি করে।
মার্টিন ওধেলিয়াস

1

উত্তরের সন্ধানে আজ এটিকে হোঁচট খেয়েছে এবং আমি ভেবেছিলাম যে আমি আমার সংস্করণটিকে তালিকায় যুক্ত করব (কোনও পাং উদ্দেশ্য নয়)। এটি সি # 6.0 এর নাল কন্ডিশনাল অপারেটরটি সারসংক্ষেপ করে

IEnumerable<Item> collection = GetTheCollection();

var index = collection
.Select((item,idx) => new { Item = item, Index = idx })
//or .FirstOrDefault(_ =>  _.Item.Prop == something)
.FirstOrDefault(_ => _.Item == itemToFind)?.Index ?? -1;

আমি কিছু 'পুরানো ঘোড়াদের রেসিং' করেছি (পরীক্ষা) এবং বড় সংগ্রহের জন্য (~ 100,000), আপনি যে আইটেমটি চান সেটি সবচেয়ে খারাপ পরিস্থিতি, এটি করা চেয়ে 2x দ্রুত ToList().FindIndex()। আপনি যে আইটেমটি চান তা যদি মাঝের দিকে হয় তবে এর x 4x দ্রুত।

ছোট সংগ্রহের জন্য (10,000 ডলার) এটি কেবলমাত্র সামান্য দ্রুত বলে মনে হচ্ছে

এগুলি আমি কীভাবে এটি পরীক্ষা করেছি https://gist.github.com/insulind/16310945247fcf13ba186a45734f254e


1

@ মার্ক গ্র্যাভেলের উত্তরটি ব্যবহার করে, আমি নিম্নলিখিত পদ্ধতিটি ব্যবহার করার একটি উপায় খুঁজে পেয়েছি:

source.TakeWhile(x => x != value).Count();

আইটেমটি পাওয়া যাবে না যখন -1 পেতে:

internal static class Utils
{

    public static int IndexOf<T>(this IEnumerable<T> enumerable, T item) => enumerable.IndexOf(item, EqualityComparer<T>.Default);

    public static int IndexOf<T>(this IEnumerable<T> enumerable, T item, EqualityComparer<T> comparer)
    {
        int index = enumerable.TakeWhile(x => comparer.Equals(x, item)).Count();
        return index == enumerable.Count() ? -1 : index;
    }
}

আমার ধারণা, এই উপায়টি দ্রুত এবং সহজতর উভয়ই হতে পারে। তবে, আমি এখনও পারফরম্যান্স পরীক্ষা করিনি।


0

তথ্যের পরে সূচকটি সন্ধানের বিকল্প হ'ল লিনক গ্রুপবি () পদ্ধতিটি ব্যবহার করার মতো কিছুটা অনুরূপ গণ্যকারীকে মোড়ানো।

public static class IndexedEnumerable
{
    public static IndexedEnumerable<T> ToIndexed<T>(this IEnumerable<T> items)
    {
        return IndexedEnumerable<T>.Create(items);
    }
}

public class IndexedEnumerable<T> : IEnumerable<IndexedEnumerable<T>.IndexedItem>
{
    private readonly IEnumerable<IndexedItem> _items;

    public IndexedEnumerable(IEnumerable<IndexedItem> items)
    {
        _items = items;
    }

    public class IndexedItem
    {
        public IndexedItem(int index, T value)
        {
            Index = index;
            Value = value;
        }

        public T Value { get; private set; }
        public int Index { get; private set; }
    }

    public static IndexedEnumerable<T> Create(IEnumerable<T> items)
    {
        return new IndexedEnumerable<T>(items.Select((item, index) => new IndexedItem(index, item)));
    }

    public IEnumerator<IndexedItem> GetEnumerator()
    {
        return _items.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

যা এর ব্যবহারের ক্ষেত্রে দেয়:

var items = new[] {1, 2, 3};
var indexedItems = items.ToIndexed();
foreach (var item in indexedItems)
{
    Console.WriteLine("items[{0}] = {1}", item.Index, item.Value);
}

দুর্দান্ত বেসলাইন এটি আইসইভেন, আইসওড, ইজফারস্ট এবং ইসলাস্ট সদস্যদের যুক্ত করতে সহায়ক।
জেজেএস

0

এটি কোনও এক্সটেনশান (প্রক্সি হিসাবে কাজ করা) এর মাধ্যমে সত্যিই শীতল হতে পারে, উদাহরণস্বরূপ:

collection.SelectWithIndex(); 
// vs. 
collection.Select((item, index) => item);

যা স্বয়ংক্রিয়ভাবে এই Indexসম্পত্তিটির মাধ্যমে অ্যাক্সেসযোগ্য সংগ্রহের সূচীগুলি নির্ধারণ করবে ।

ইন্টারফেস:

public interface IIndexable
{
    int Index { get; set; }
}

কাস্টম এক্সটেনশন (সম্ভবত EF এবং DbContext সঙ্গে কাজ করার জন্য সবচেয়ে দরকারী):

public static class EnumerableXtensions
{
    public static IEnumerable<TModel> SelectWithIndex<TModel>(
        this IEnumerable<TModel> collection) where TModel : class, IIndexable
    {
        return collection.Select((item, index) =>
        {
            item.Index = index;
            return item;
        });
    }
}

public class SomeModelDTO : IIndexable
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }

    public int Index { get; set; }
}

// In a method
var items = from a in db.SomeTable
            where a.Id == someValue
            select new SomeModelDTO
            {
                Id = a.Id,
                Name = a.Name,
                Price = a.Price
            };

return items.SelectWithIndex()
            .OrderBy(m => m.Name)
            .Skip(pageStart)
            .Take(pageSize)
            .ToList();
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.