সেগুলিতে আইটেমের ক্রম নির্বিশেষে সমতার জন্য দুটি সংগ্রহের তুলনা করা


162

আমি দুটি সংগ্রহের তুলনা করতে চাই (সি # তে), তবে এটিকে দক্ষতার সাথে কার্যকর করার সর্বোত্তম উপায় সম্পর্কে আমি নিশ্চিত নই।

আমি এনুম্যুয়েবল.সিকোয়েন্সএকুয়াল সম্পর্কে অন্যান্য থ্রেডটি পড়েছি , তবে এটি ঠিক যা খুঁজছি তা নয়।

আমার ক্ষেত্রে, দুটি সংগ্রহ সমান হবে যদি সেগুলির মধ্যে উভয়ই একই আইটেম থাকে (অর্ডার বিবেচনা না করে)।

উদাহরণ:

collection1 = {1, 2, 3, 4};
collection2 = {2, 4, 1, 3};

collection1 == collection2; // true

আমি সাধারণত যা করি তা হ'ল একটি সংগ্রহের প্রতিটি আইটেম লুপ করা এবং এটি অন্য সংগ্রহে উপস্থিত রয়েছে কিনা তা দেখুন, তবে অন্য সংগ্রহের প্রতিটি আইটেমের মধ্য দিয়ে লুপ করুন এবং দেখুন যে এটি প্রথম সংকলনে বিদ্যমান রয়েছে কিনা। (আমি দৈর্ঘ্যের তুলনা করে শুরু করি)।

if (collection1.Count != collection2.Count)
    return false; // the collections are not equal

foreach (Item item in collection1)
{
    if (!collection2.Contains(item))
        return false; // the collections are not equal
}

foreach (Item item in collection2)
{
    if (!collection1.Contains(item))
        return false; // the collections are not equal
}

return true; // the collections are equal

তবে এটি পুরোপুরি সঠিক নয় এবং এটি সম্ভবত সমতার জন্য দুটি সংগ্রহের তুলনা করার সবচেয়ে কার্যকর উপায় নয়।

এটির জন্য ভুল হতে পারে এমন একটি উদাহরণ হ'ল:

collection1 = {1, 2, 3, 3, 4}
collection2 = {1, 2, 2, 3, 4}

যা আমার বাস্তবায়নের সাথে সমান হবে। প্রতিটি আইটেমের সন্ধানের পরিমাণটি কি কেবল গণনা করা উচিত এবং উভয় সংকলনে গণনা সমান কিনা তা নিশ্চিত করা উচিত?


উদাহরণগুলি কিছুটা সি # তে রয়েছে (আসুন একে সিউডো-সি # বলুন) তবে আপনি যে ভাষায় ইচ্ছুক উত্তর দিন, তাতে কিছু যায় আসে না।

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


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

আপনি যে সমতার জন্য যাচাই করছেন সেই সমতার জন্য আপনি যাচাই করছেন না। এটি নিটপিকি কিন্তু একটি গুরুত্বপূর্ণ পার্থক্য। এবং অনেক দিন আগে। এটি একটি ভাল প্রশ্ন + এ।
সিএডি

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

উত্তর:


112

দেখা যাচ্ছে যে মাইক্রোসফ্ট ইতিমধ্যে এটির পরীক্ষার কাঠামোর আওতায় রয়েছে: কালেকশনএসার্ট.আরএকুইভ্যালেন্ট

মন্তব্য

দুটি সংগ্রহ সমান হয় যদি তাদের একই পরিমাণে একই উপাদান থাকে তবে কোনও ক্রমে। উপাদানগুলি সমান হয় যদি তাদের মানগুলি সমান হয় তবে তারা একই বস্তুর উল্লেখ করে না।

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

public class MultiSetComparer<T> : IEqualityComparer<IEnumerable<T>>
{
    private readonly IEqualityComparer<T> m_comparer;
    public MultiSetComparer(IEqualityComparer<T> comparer = null)
    {
        m_comparer = comparer ?? EqualityComparer<T>.Default;
    }

    public bool Equals(IEnumerable<T> first, IEnumerable<T> second)
    {
        if (first == null)
            return second == null;

        if (second == null)
            return false;

        if (ReferenceEquals(first, second))
            return true;

        if (first is ICollection<T> firstCollection && second is ICollection<T> secondCollection)
        {
            if (firstCollection.Count != secondCollection.Count)
                return false;

            if (firstCollection.Count == 0)
                return true;
        }

        return !HaveMismatchedElement(first, second);
    }

    private bool HaveMismatchedElement(IEnumerable<T> first, IEnumerable<T> second)
    {
        int firstNullCount;
        int secondNullCount;

        var firstElementCounts = GetElementCounts(first, out firstNullCount);
        var secondElementCounts = GetElementCounts(second, out secondNullCount);

        if (firstNullCount != secondNullCount || firstElementCounts.Count != secondElementCounts.Count)
            return true;

        foreach (var kvp in firstElementCounts)
        {
            var firstElementCount = kvp.Value;
            int secondElementCount;
            secondElementCounts.TryGetValue(kvp.Key, out secondElementCount);

            if (firstElementCount != secondElementCount)
                return true;
        }

        return false;
    }

    private Dictionary<T, int> GetElementCounts(IEnumerable<T> enumerable, out int nullCount)
    {
        var dictionary = new Dictionary<T, int>(m_comparer);
        nullCount = 0;

        foreach (T element in enumerable)
        {
            if (element == null)
            {
                nullCount++;
            }
            else
            {
                int num;
                dictionary.TryGetValue(element, out num);
                num++;
                dictionary[element] = num;
            }
        }

        return dictionary;
    }

    public int GetHashCode(IEnumerable<T> enumerable)
    {
        if (enumerable == null) throw new ArgumentNullException(nameof(enumerable));

        int hash = 17;

        foreach (T val in enumerable.OrderBy(x => x))
            hash = hash * 23 + (val?.GetHashCode() ?? 42);

        return hash;
    }
}

নমুনা ব্যবহার:

var set = new HashSet<IEnumerable<int>>(new[] {new[]{1,2,3}}, new MultiSetComparer<int>());
Console.WriteLine(set.Contains(new [] {3,2,1})); //true
Console.WriteLine(set.Contains(new [] {1, 2, 3, 3})); //false

অথবা আপনি যদি সরাসরি দুটি সংগ্রহের তুলনা করতে চান তবে:

var comp = new MultiSetComparer<string>();
Console.WriteLine(comp.Equals(new[] {"a","b","c"}, new[] {"a","c","b"})); //true
Console.WriteLine(comp.Equals(new[] {"a","b","c"}, new[] {"a","b"})); //false

অবশেষে, আপনি নিজের পছন্দটির সমতা তুলনামূলক ব্যবহার করতে পারেন:

var strcomp = new MultiSetComparer<string>(StringComparer.OrdinalIgnoreCase);
Console.WriteLine(strcomp.Equals(new[] {"a", "b"}, new []{"B", "A"})); //true

7
আমি ১০০% নিশ্চিত নই তবে আমি মনে করি আপনার উত্তরটি বিপরীত প্রকৌশলের বিরুদ্ধে মাইক্রোসফ্টের ব্যবহারের শর্তাদি লঙ্ঘন করেছে।
ইয়ান ডালাস

1
হ্যালো ওহদ, অনুগ্রহ করে বিষয় নিম্নলিখিত দীর্ঘ বিতর্ক পড়তে stackoverflow.com/questions/371328/... আপনি, বস্তুর হ্যাশকোড পরিবর্তন করেন তাহলে যখন তার একটি hashset এটা hashset সঠিক কাজের সঙ্গে সাময়িক বিরতি হবে এবং একটি ব্যতিক্রম হতে পারে। নিয়মটি নিম্নরূপ: দুটি বস্তু সমান হলে - তাদের অবশ্যই হ্যাশ কোড থাকতে হবে। দুটি বস্তুর যদি একই হ্যাশকোড থাকে - তাদের সমান হওয়া জরুরী নয়। হ্যাশকোড অবশ্যই পুরো অবজেক্টের জীবদ্দশায় একই থাকবে! আপনি ICompareable এবং আইক্যালোরিটি কেন প্ররোচিত করেন তা ঠিক ts
জেমস রোইটার

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

1
@ জামেসরোয়েটার ধরুন এক্স এবং ওয়াই দুটি জিনিস যা আমরা তুলনা করতে চাই। যদি তাদের আলাদা হ্যাশকোড থাকে তবে আমরা জানি যে তারা আলাদা (কারণ সমান আইটেমগুলির সমান হ্যাশকোড রয়েছে) এবং উপরের প্রয়োগটি সঠিক। তাদের যদি একই হ্যাশকোড থাকে তবে অভিধান প্রয়োগটি নির্দিষ্ট (অথবা যদি নির্দিষ্ট না হয়) ব্যবহার করে প্রকৃত সাম্যতা পরীক্ষা করে এবং আবার প্রয়োগটি সঠিক হয়। EqualityComparerEqualityComparer.Default
ওহাদ স্নাইডার

1
ইন্টারফেসের Equalsকারণে @ সিএডি ব্লক পদ্ধতিটির নামকরণ করতে হবে IEqualityComparer<T>। আপনার যা দেখার উচিত তা হ'ল তুলনাকারীর নাম । এই ক্ষেত্রে এটি MultiSetComparerবোঝা যায় যা।
ওহাদ স্নাইডার

98

একটি সহজ এবং মোটামুটি দক্ষ সমাধান হ'ল উভয় সংগ্রহকে বাছাই করা এবং তারপরে তাদের সমতার জন্য তুলনা করা:

bool equal = collection1.OrderBy(i => i).SequenceEqual(
                 collection2.OrderBy(i => i));

এই অ্যালগরিদমটি হ'ল (এন * লগএন), যখন আপনার উপরের সমাধানটি ও (এন ^ 2)।

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


1
আপনাকে কেবল সিস্টেম.লিনক ব্যবহার করে যুক্ত করতে হবে; এটি কার্যকর করার জন্য প্রথম
জুনিয়র মেহে

যদি এই কোডটি একটি লুপের মধ্যে থাকে এবং সংগ্রহ 1 আপডেট হয়ে যায় এবং সংগ্রহ 2 অপরিবর্তিত থাকে, তবে উভয় সংগ্রহের একই অবজেক্ট থাকা সত্ত্বেও লক্ষ্য করুন, ডিবাগার এই "সমান" ভেরিয়েবলের জন্য মিথ্যা প্রদর্শন করবে।
জুনিয়র মেহে

5
@ চাউলকি - আমি বিশ্বাস করি অর্ডারবাইয়ের প্রয়োজন। দেখুন: dotnetfiddle.net/jA8iwE
ব্রেট

"উত্তর" হিসাবে উল্লেখ করা অন্যান্য উত্তর কোনটি ছিল? সম্ভবত স্ট্যাকওভারফ্লো . com/a/50465/3195477 ?
ইউডিডিএলআরএলআরএস

32

একটি অভিধান "ডিক" তৈরি করুন এবং তারপরে প্রথম সংগ্রহের প্রতিটি সদস্যের জন্য ডিক [সদস্য] ++ করুন;

তারপরে, দ্বিতীয় সংগ্রহটি একইভাবে লুপ করুন তবে প্রতিটি সদস্যের জন্য ডিক [সদস্য] করুন -।

শেষে, অভিধানে থাকা সমস্ত সদস্যকে লুপ করুন:

    private bool SetEqual (List<int> left, List<int> right) {

        if (left.Count != right.Count)
            return false;

        Dictionary<int, int> dict = new Dictionary<int, int>();

        foreach (int member in left) {
            if (dict.ContainsKey(member) == false)
                dict[member] = 1;
            else
                dict[member]++;
        }

        foreach (int member in right) {
            if (dict.ContainsKey(member) == false)
                return false;
            else
                dict[member]--;
        }

        foreach (KeyValuePair<int, int> kvp in dict) {
            if (kvp.Value != 0)
                return false;
        }

        return true;

    }

সম্পাদনা: যতদূর আমি এটি বলতে পারি সবচেয়ে কার্যকর অ্যালগরিদম হিসাবে একই আদেশে। এই অ্যালগরিদমটি হ'ল হে (এন), ধরে নিচ্ছেন যে অভিধানটি ও (1) লুপ ব্যবহার করে।


এটি প্রায় আমি চাই তবে, আমি পূর্ণসংখ্যার ব্যবহার না করেও এটি করতে সক্ষম হতে চাই to আমি রেফারেন্স অবজেক্ট ব্যবহার করতে চাই, তবে তারা অভিধানগুলির কী হিসাবে সঠিকভাবে আচরণ করে না।
mbillard

মনো, যদি আপনার আইটেমগুলি তুলনাযোগ্য না হয় তবে আপনার প্রশ্নটি স্থির। সেগুলি অভিধানে কী হিসাবে ব্যবহার করতে না পারলে কোনও সমাধান পাওয়া যায় না।
স্কোলিমা

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

সহায়তার জন্য অবশ্যই উত্সাহিত, তবে এটি একটি গুরুত্বপূর্ণ পয়েন্ট (যা আমি আমার উত্তরে কভার করছি) অনুপস্থিত থেকে গ্রহণযোগ্য নয়।
mbillard

1
এফডাব্লুআইডাব্লু, আপনি আপনার শেষ ফোরচ লুপটি সহজ করতে পারেন এবং এর সাথে বিবৃতিটি ফেরত দিতে পারেন:return dict.All(kvp => kvp.Value == 0);
টাইসন উইলিয়ামস

18

এটি আমার (ডি জেনিংস দ্বারা ব্যাপকভাবে প্রভাবিত) তুলনা পদ্ধতির জেনেরিক প্রয়োগ (সি # তে):

/// <summary>
/// Represents a service used to compare two collections for equality.
/// </summary>
/// <typeparam name="T">The type of the items in the collections.</typeparam>
public class CollectionComparer<T>
{
    /// <summary>
    /// Compares the content of two collections for equality.
    /// </summary>
    /// <param name="foo">The first collection.</param>
    /// <param name="bar">The second collection.</param>
    /// <returns>True if both collections have the same content, false otherwise.</returns>
    public bool Execute(ICollection<T> foo, ICollection<T> bar)
    {
        // Declare a dictionary to count the occurence of the items in the collection
        Dictionary<T, int> itemCounts = new Dictionary<T,int>();

        // Increase the count for each occurence of the item in the first collection
        foreach (T item in foo)
        {
            if (itemCounts.ContainsKey(item))
            {
                itemCounts[item]++;
            }
            else
            {
                itemCounts[item] = 1;
            }
        }

        // Wrap the keys in a searchable list
        List<T> keys = new List<T>(itemCounts.Keys);

        // Decrease the count for each occurence of the item in the second collection
        foreach (T item in bar)
        {
            // Try to find a key for the item
            // The keys of a dictionary are compared by reference, so we have to
            // find the original key that is equivalent to the "item"
            // You may want to override ".Equals" to define what it means for
            // two "T" objects to be equal
            T key = keys.Find(
                delegate(T listKey)
                {
                    return listKey.Equals(item);
                });

            // Check if a key was found
            if(key != null)
            {
                itemCounts[key]--;
            }
            else
            {
                // There was no occurence of this item in the first collection, thus the collections are not equal
                return false;
            }
        }

        // The count of each item should be 0 if the contents of the collections are equal
        foreach (int value in itemCounts.Values)
        {
            if (value != 0)
            {
                return false;
            }
        }

        // The collections are equal
        return true;
    }
}

12
দারুন কাজ, তবে দ্রষ্টব্য: ১. ড্যানিয়েল জেনিংস সমাধানের বিপরীতে, বার সংগ্রহের পূর্ববর্তী লুপের ভিতরে ফাংশনটি অনুসন্ধানের কারণে এটি ও (এন) নয় বরং ও (এন ^ 2); ২. কোডটিতে আর কোনও পরিবর্তন না করে আপনি আইকোলিকেশন <T> এর পরিবর্তে আইনিউমেবল <T> গ্রহণের পদ্ধতিটি সাধারণ করতে পারেন
ওহাদ স্নাইডার

The keys of a dictionary are compared by reference, so we have to find the original key that is equivalent to the "item"- এটা সত্য নয়। অ্যালগরিদম ভুল অনুমানের উপর ভিত্তি করে এবং কাজ করার সময়, এটি মারাত্মকভাবে অক্ষম।
আন্তোনোন লেজসেক

10

আপনি একটি হ্যাশসেট ব্যবহার করতে পারেন । এ SetEquals পদ্ধতি।


2
অবশ্যই, হ্যাশসেট ব্যবহার করে কোনও সদৃশ অনুমান করা যায় তবে তাই হ্যাশসেটই যাওয়ার সবচেয়ে ভাল উপায়
মার্ক সিডাড

7

যদি আপনি শোল্ডলি ব্যবহার করেন তবে আপনি কন্টেন্ট সহ উইথএলবি ব্যবহার করতে পারেন।

collection1 = {1, 2, 3, 4};
collection2 = {2, 4, 1, 3};

collection1.ShouldAllBe(item=>collection2.Contains(item)); // true

এবং অবশেষে, আপনি একটি এক্সটেনশন লিখতে পারেন।

public static class ShouldlyIEnumerableExtensions
{
    public static void ShouldEquivalentTo<T>(this IEnumerable<T> list, IEnumerable<T> equivalent)
    {
        list.ShouldAllBe(l => equivalent.Contains(l));
    }
}

হালনাগাদ

হোল্ডবি পদ্ধতিতে একটি alচ্ছিক প্যারামিটার বিদ্যমান ।

collection1.ShouldBe(collection2, ignoreOrder: true); // true

1
আমি সবেমাত্র সর্বশেষতম সংস্করণে পেয়েছি যে হোল্ডবি পদ্ধতিতে একটি প্যারামিটার bool ignoreOrderরয়েছে ।
পিয়ের-লিওনেল এসগার্ড

5

সম্পাদনা: আমি যখনই বুঝতে পেরেছিলাম যে এটি সত্যিই কেবল সেটগুলির জন্য কাজ করে - এটি নকল আইটেমগুলি সহ সংগ্রহের সাথে সঠিকভাবে মোকাবেলা করবে না। উদাহরণস্বরূপ {1, 1, 2} এবং {2, 2, 1 এই অ্যালগরিদমের দৃষ্টিকোণ থেকে সমান বিবেচিত হবে। যদি আপনার সংগ্রহগুলি সেট হয় (বা তাদের সমতাটি সেভাবে পরিমাপ করা যায়) তবে আমি আশা করি আপনি নীচেরটিকে দরকারী বলে মনে করেন।

আমি যে সমাধানটি ব্যবহার করি তা হ'ল:

return c1.Count == c2.Count && c1.Intersect(c2).Count() == c1.Count;

লিনক অভিধানের কাজগুলি কভারগুলির নীচে করে তাই এটি ও (এন) হয়। (দ্রষ্টব্য, সংগ্রহগুলি একই আকারের না হলে এটি ও (1))।

আমি ড্যানিয়েলের প্রস্তাবিত "সেটএকুয়াল" পদ্ধতি, ইগর দ্বারা প্রস্তাবিত অর্ডারবাই / সিকোয়েন্সএকুয়ালস পদ্ধতি এবং আমার পরামর্শ ব্যবহার করে স্যানিটি চেক করেছি। ফলাফলগুলি নীচে রয়েছে, ইগোরের জন্য ও (এন * লগএন) এবং খনি এবং ড্যানিয়েলের জন্য ও (এন) দেখাচ্ছে।

আমি মনে করি লিনক ছেদ কোডটির সরলতা এটিকে পছন্দসই সমাধান করে তোলে।

__Test Latency(ms)__
N, SetEquals, OrderBy, Intersect    
1024, 0, 0, 0    
2048, 0, 0, 0    
4096, 31.2468, 0, 0    
8192, 62.4936, 0, 0    
16384, 156.234, 15.6234, 0    
32768, 312.468, 15.6234, 46.8702    
65536, 640.5594, 46.8702, 31.2468    
131072, 1312.3656, 93.7404, 203.1042    
262144, 3765.2394, 187.4808, 187.4808    
524288, 5718.1644, 374.9616, 406.2084    
1048576, 11420.7054, 734.2998, 718.6764    
2097152, 35090.1564, 1515.4698, 1484.223

এই কোডটির সাথে একমাত্র সমস্যাটি হ'ল কেবলমাত্র মান ধরণের তুলনা করতে বা পয়েন্টারগুলিকে রেফারেন্স ধরণের সাথে তুলনা করার সময় কাজ করে। সংগ্রহগুলিতে আমার একই বস্তুর দুটি পৃথক দৃষ্টান্ত থাকতে পারে, সুতরাং প্রতিটি কীভাবে তুলনা করতে হবে তা নির্দিষ্ট করতে আমার সক্ষম হওয়া দরকার। ছেদ করার পদ্ধতিতে আপনি কি তুলনা প্রতিনিধি পাস করতে পারেন?
এমবিলার্ড

অবশ্যই, আপনি একটি তুলনামূলক প্রতিনিধি পাস করতে পারেন। তবে, আমি যে সেটগুলি যোগ করেছি সেগুলি সম্পর্কে উপরের সীমাবদ্ধতাটি নোট করুন, যা এর প্রয়োগযোগ্যতার উপর উল্লেখযোগ্য সীমা রাখে।

ছেদ পদ্ধতিটি একটি পৃথক সংগ্রহ প্রদান করে। একটি = {1,1,2} এবং খ = {2,2,1}, a.Intersect (খ) .আরঙ্ক ()! = এ। {1,2} .Count = {1,1,2} .Count দেখুন! লিংক [/ লিংক] (দ্রষ্টব্য যে উভয় পক্ষের তুলনা আগে স্বতন্ত্র তৈরি করা হয়।)
গ্রিফিন

5

পুনরাবৃত্তি না করা এবং কোনও আদেশ না দেওয়ার ক্ষেত্রে, নিম্নলিখিত ইক্যুয়ালিটি কম্প্যাকারিকে অভিধান কী হিসাবে সংগ্রহের অনুমতি দেওয়ার জন্য ব্যবহার করা যেতে পারে:

public class SetComparer<T> : IEqualityComparer<IEnumerable<T>> 
where T:IComparable<T>
{
    public bool Equals(IEnumerable<T> first, IEnumerable<T> second)
    {
        if (first == second)
            return true;
        if ((first == null) || (second == null))
            return false;
        return first.ToHashSet().SetEquals(second);
    }

    public int GetHashCode(IEnumerable<T> enumerable)
    {
        int hash = 17;

        foreach (T val in enumerable.OrderBy(x => x))
            hash = hash * 23 + val.GetHashCode();

        return hash;
    }
}

এখানে আমি ব্যবহৃত টোহ্যাশসেট () প্রয়োগকরণ। হ্যাশ কোড অ্যালগরিদম (জন স্কিট প্রণালী দ্বারা) কার্যকরী জাভা থেকে আসে।


তুলনামূলক ক্লাসের সিরিয়ালাইজেবলের বিন্দুটি কী? : o এছাড়াও আপনি ইনপুটটি ISet<T>প্রকাশ করতে এটি সেট করার জন্য বোঝাতে পারেন (অর্থাত্ কোনও নকল নেই)।
নওফাল

@ নওফাল ধন্যবাদ, আমি যখন সিরিয়ালিটেবল হিসাবে চিহ্নিত করলাম তখন আমি কী ভাবছিলাম তা জানেন না ... তবে ISetএখানে ধারণাটি ছিল IEnumerableএকটি সেট হিসাবে বিবেচনা করা (কারণ আপনি IEnumerableশুরু করতে পেরেছিলেন ), যদিও ওভারে 0 টি উর্ধ্বতন বিবেচনা করে 5 বছর যা তীক্ষ্ণ ধারণাটি নাও হতে পারে: পি
ওহাদ স্নাইডার

4
static bool SetsContainSameElements<T>(IEnumerable<T> set1, IEnumerable<T> set2) {
    var setXOR = new HashSet<T>(set1);
    setXOR.SymmetricExceptWith(set2);
    return (setXOR.Count == 0);
}

সমাধানের জন্য .NET 3.5 এবং System.Collections.Genericনেমস্পেসের প্রয়োজন। মাইক্রোসফ্টের মতে , SymmetricExceptWithএকটি ও (এন + মি) অপারেশন, এনটি প্রথম সেটটিতে উপাদানগুলির সংখ্যার প্রতিনিধিত্ব করে এবং দ্বিতীয়টি উপাদানের সংখ্যার প্রতিনিধিত্ব করে এম । আপনি প্রয়োজনে এই ক্রিয়ায় সর্বদা একটি সমতা তুলক যুক্ত করতে পারেন।


3

কেন ব্যবহার করবেন না। বাদে ()

// Create the IEnumerable data sources.
string[] names1 = System.IO.File.ReadAllLines(@"../../../names1.txt");
string[] names2 = System.IO.File.ReadAllLines(@"../../../names2.txt");
// Create the query. Note that method syntax must be used here.
IEnumerable<string> differenceQuery =   names1.Except(names2);
// Execute the query.
Console.WriteLine("The following lines are in names1.txt but not names2.txt");
foreach (string s in differenceQuery)
     Console.WriteLine(s);

http://msdn.microsoft.com/en-us/library/bb397894.aspx


2
Exceptসদৃশ আইটেম গণনা করার জন্য কাজ করবে না। এটি sets 1,2,2 sets এবং {1,1,2 sets সেটগুলির জন্য সত্য ফিরে আসবে}
ক্রিশ্চিয়ান ডায়াকোনস্কু

@ ক্রিসিটি ডায়াকোনস্কু আপনি কোনও নকল অপসারণ করতে প্রথমে ".ডিসিন্টিন্ট ()" করতে পারেন
কোরাইয়েম

ওপি চাইছে [1, 1, 2] != [1, 2, 2]। ব্যবহারগুলি Distinctতাদের সমান দেখায়।
ক্রিশ্চিয়ান ডায়াকোনস্কু

2

প্রকারের একটি সদৃশ পোস্ট, তবে সংগ্রহের তুলনা করার জন্য আমার সমাধানটি দেখুন । এটি বেশ সহজ:

এটি অর্ডার নির্বিশেষে সমতার তুলনা সম্পাদন করবে:

var list1 = new[] { "Bill", "Bob", "Sally" };
var list2 = new[] { "Bob", "Bill", "Sally" };
bool isequal = list1.Compare(list2).IsSame;

এটি আইটেমগুলি যুক্ত / অপসারণ করা হয়েছে কিনা তা পরীক্ষা করবে:

var list1 = new[] { "Billy", "Bob" };
var list2 = new[] { "Bob", "Sally" };
var diff = list1.Compare(list2);
var onlyinlist1 = diff.Removed; //Billy
var onlyinlist2 = diff.Added;   //Sally
var inbothlists = diff.Equal;   //Bob

এটি অভিধানে কী আইটেম পরিবর্তিত হয়েছে তা দেখতে পাবে:

var original = new Dictionary<int, string>() { { 1, "a" }, { 2, "b" } };
var changed = new Dictionary<int, string>() { { 1, "aaa" }, { 2, "b" } };
var diff = original.Compare(changed, (x, y) => x.Value == y.Value, (x, y) => x.Value == y.Value);
foreach (var item in diff.Different)
  Console.Write("{0} changed to {1}", item.Key.Value, item.Value.Value);
//Will output: a changed to aaa

মূল পোস্ট এখানে


1

এরিকসন প্রায় সঠিক: যেহেতু আপনি নকলের সংখ্যার সাথে মিল রাখতে চান, আপনি একটি ব্যাগ চান । জাভাতে, এরকম কিছু দেখাচ্ছে:

(new HashBag(collection1)).equals(new HashBag(collection2))

আমি নিশ্চিত যে সি # এর একটি অন্তর্নির্মিত সেট বাস্তবায়ন রয়েছে। আমি প্রথমে এটি ব্যবহার করব; কর্মক্ষমতা যদি সমস্যা হয় তবে আপনি সর্বদা আলাদা সেট প্রয়োগ ব্যবহার করতে পারেন তবে একই সেট ইন্টারফেসটি ব্যবহার করতে পারেন।


1

এখানে আমার প্রসারণের পদ্ধতিটি ওড্ডসকের উত্তরের বৈকল্পিক, যদি কারওর পক্ষে এটি কার্যকর হয়

static public class EnumerableExtensions 
{
    static public bool IsEquivalentTo<T>(this IEnumerable<T> first, IEnumerable<T> second)
    {
        if ((first == null) != (second == null))
            return false;

        if (!object.ReferenceEquals(first, second) && (first != null))
        {
            if (first.Count() != second.Count())
                return false;

            if ((first.Count() != 0) && HaveMismatchedElement<T>(first, second))
                return false;
        }

        return true;
    }

    private static bool HaveMismatchedElement<T>(IEnumerable<T> first, IEnumerable<T> second)
    {
        int firstCount;
        int secondCount;

        var firstElementCounts = GetElementCounts<T>(first, out firstCount);
        var secondElementCounts = GetElementCounts<T>(second, out secondCount);

        if (firstCount != secondCount)
            return true;

        foreach (var kvp in firstElementCounts)
        {
            firstCount = kvp.Value;
            secondElementCounts.TryGetValue(kvp.Key, out secondCount);

            if (firstCount != secondCount)
                return true;
        }

        return false;
    }

    private static Dictionary<T, int> GetElementCounts<T>(IEnumerable<T> enumerable, out int nullCount)
    {
        var dictionary = new Dictionary<T, int>();
        nullCount = 0;

        foreach (T element in enumerable)
        {
            if (element == null)
            {
                nullCount++;
            }
            else
            {
                int num;
                dictionary.TryGetValue(element, out num);
                num++;
                dictionary[element] = num;
            }
        }

        return dictionary;
    }

    static private int GetHashCode<T>(IEnumerable<T> enumerable)
    {
        int hash = 17;

        foreach (T val in enumerable.OrderBy(x => x))
            hash = hash * 23 + val.GetHashCode();

        return hash;
    }
}

এটি কতটা ভালভাবে সম্পাদন করে, কোনও ধারণা?
নওফাল

আমি এটি কেবল ছোট সংগ্রহের জন্যই ব্যবহার করি, তাই বিগ-ও জটিলতা বা বেঞ্চমার্কিংয়ের কথা ভাবেননি। HaveMismatchedElements একা হ'ল O (M * N) তাই এটি বড় সংগ্রহের জন্য ভাল পারফরম্যান্স নাও করতে পারে।
এরিক জে।

যদি IEnumerable<T>গুলি জিজ্ঞাসা হয় তবে কল Count()করা ভাল ধারণা নয়। ওহাদের মূল উত্তরের চেক করার পদ্ধতির তারা কিনা তা আরও ICollection<T>ভাল ধারণা।
নওফাল

1

এখানে একটি সমাধান যার উপর একটি উন্নতি হয় এই এক

public static bool HasSameElementsAs<T>(
        this IEnumerable<T> first, 
        IEnumerable<T> second, 
        IEqualityComparer<T> comparer = null)
    {
        var firstMap = first
            .GroupBy(x => x, comparer)
            .ToDictionary(x => x.Key, x => x.Count(), comparer);

        var secondMap = second
            .GroupBy(x => x, comparer)
            .ToDictionary(x => x.Key, x => x.Count(), comparer);

        if (firstMap.Keys.Count != secondMap.Keys.Count)
            return false;

        if (firstMap.Keys.Any(k1 => !secondMap.ContainsKey(k1)))
            return false;

        return firstMap.Keys.All(x => firstMap[x] == secondMap[x]);
    }

0

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


0

অনেক ক্ষেত্রে একমাত্র উপযুক্ত উত্তর হ'ল ইগর ওস্ট্রভস্কির মধ্যে একটি, অন্যান্য উত্তরগুলি হ্যাজ কোডের উপর ভিত্তি করে। কিন্তু যখন আপনি কোনও অবজেক্টের জন্য একটি হ্যাশ কোড তৈরি করেন আপনি কেবল তার অপ্রত্যাশিত ক্ষেত্রের উপর ভিত্তি করে করেন - যেমন বস্তু আইডি ক্ষেত্র (কোনও ডাটাবেস সত্তার ক্ষেত্রে) - যখন সমান পদ্ধতিটি ওভাররাইড করা হয় তখন গেটহ্যাশকোডকে ওভাররাইড করা কেন গুরুত্বপূর্ণ?

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

তার সবচেয়ে বেশি পোষ্ট পোস্টে আমার এবং মিঃ স্কিনাইডারের মন্তব্যগুলি পড়ুন।

জেমস


0

নকলের জন্য অনুমতি দেয় IEnumerable<T>(যদি সেটগুলি পছন্দসই হয় না \ সম্ভব) এবং "আদেশ অগ্রাহ্য করার" জন্য আপনি একটি ব্যবহার করতে সক্ষম হবেন.GroupBy()

আমি জটিলতা পরিমাপের বিশেষজ্ঞ নই, তবে আমার প্রাথমিক বোঝাপড়াটি হ'ল এটি ও (এন) হওয়া উচিত। আমি O (n ^ 2) এর মতো অন্য O (n) অপারেশনের মতো কোনও O (n) ক্রিয়া সম্পাদন করে আসা হিসাবে বুঝতে পারি understandListA.Where(a => ListB.Contains(a)).ToList() । তালিকার প্রতিটি আইটেমের তালিকার প্রতিটি আইটের বিপরীতে সমতার জন্য মূল্যায়ন করা হয়।

যেমনটি আমি বলেছিলাম, জটিলতার বিষয়ে আমার বোঝা সীমিত, সুতরাং আমি যদি ভুল হয়ে থাকি তবে আমাকে এটিকে সংশোধন করুন।

public static bool IsSameAs<T, TKey>(this IEnumerable<T> source, IEnumerable<T> target, Expression<Func<T, TKey>> keySelectorExpression)
    {
        // check the object
        if (source == null && target == null) return true;
        if (source == null || target == null) return false;

        var sourceList = source.ToList();
        var targetList = target.ToList();

        // check the list count :: { 1,1,1 } != { 1,1,1,1 }
        if (sourceList.Count != targetList.Count) return false;

        var keySelector = keySelectorExpression.Compile();
        var groupedSourceList = sourceList.GroupBy(keySelector).ToList();
        var groupedTargetList = targetList.GroupBy(keySelector).ToList();

        // check that the number of grouptings match :: { 1,1,2,3,4 } != { 1,1,2,3,4,5 }
        var groupCountIsSame = groupedSourceList.Count == groupedTargetList.Count;
        if (!groupCountIsSame) return false;

        // check that the count of each group in source has the same count in target :: for values { 1,1,2,3,4 } & { 1,1,1,2,3,4 }
        // key:count
        // { 1:2, 2:1, 3:1, 4:1 } != { 1:3, 2:1, 3:1, 4:1 }
        var countsMissmatch = groupedSourceList.Any(sourceGroup =>
                                                        {
                                                            var targetGroup = groupedTargetList.Single(y => y.Key.Equals(sourceGroup.Key));
                                                            return sourceGroup.Count() != targetGroup.Count();
                                                        });
        return !countsMissmatch;
    }

0

এই সাধারণ সমাধানটিIEnumerable এর জেনেরিক ধরণের প্রয়োগ করতে বাধ্য করে IComparable। কারণে OrderBy এর সংজ্ঞা।

আপনি যদি এই ধরনের অনুমান করতে না চান তবে এখনও এই সমাধানটি ব্যবহার করতে চান তবে আপনি নীচের কোডটির টুকরোটি ব্যবহার করতে পারেন:

bool equal = collection1.OrderBy(i => i?.GetHashCode())
   .SequenceEqual(collection2.OrderBy(i => i?.GetHashCode()));

0

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

ব্যবহার:

using Microsoft.VisualStudio.TestTools.UnitTesting;

// define collection1, collection2, ...

Assert.Equal(collection1.OrderBy(c=>c).ToCsv(), collection2.OrderBy(c=>c).ToCsv());

সহায়ক সম্প্রসারণ পদ্ধতি:

public static string ToCsv<T>(
    this IEnumerable<T> values,
    Func<T, string> selector,
    string joinSeparator = ",")
{
    if (selector == null)
    {
        if (typeof(T) == typeof(Int16) ||
            typeof(T) == typeof(Int32) ||
            typeof(T) == typeof(Int64))
        {
            selector = (v) => Convert.ToInt64(v).ToStringInvariant();
        }
        else if (typeof(T) == typeof(decimal))
        {
            selector = (v) => Convert.ToDecimal(v).ToStringInvariant();
        }
        else if (typeof(T) == typeof(float) ||
                typeof(T) == typeof(double))
        {
            selector = (v) => Convert.ToDouble(v).ToString(CultureInfo.InvariantCulture);
        }
        else
        {
            selector = (v) => v.ToString();
        }
    }

    return String.Join(joinSeparator, values.Select(v => selector(v)));
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.