সংগ্রহের তুলনা করার জন্য কি অন্তর্নির্মিত পদ্ধতি আছে?


178

আমি আমার সমান পদ্ধতিতে কয়েকটি সংগ্রহের সামগ্রীর তুলনা করতে চাই। আমার কাছে একটি অভিধান এবং একটি আইলিস্ট রয়েছে। এটি করার জন্য কোনও বিল্ট-ইন পদ্ধতি আছে?

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


অর্ডার নির্বিশেষে বা না IList? প্রশ্ন অস্পষ্ট।
নওফাল

Enumerable.SequenceEqualএবং ISet.SetEqualsএই কার্যকারিতা সংস্করণ সরবরাহ। আপনি যদি অর্ডার-অজোনস্টিক হতে চান এবং অনুলিপিযুক্ত সংগ্রহগুলি নিয়ে কাজ করতে চান তবে আপনার নিজের রোল করতে হবে। এই পোস্টে
চেসমেডালিয়ন

উত্তর:


185

Enumerable.SequenceEqual

নির্দিষ্ট আইকোয়ালিটি কম্পিউটার (টি) ব্যবহার করে তাদের উপাদানগুলির সাথে তুলনা করে দুটি ক্রম সমান কিনা তা নির্ধারণ করে।

আপনি সরাসরি তালিকা এবং অভিধানের তুলনা করতে পারবেন না, তবে আপনি অভিধান থেকে মানগুলির তালিকার সাথে তালিকার তুলনা করতে পারেন


52
সমস্যাটি হচ্ছে সিকোয়েন্সএকুয়াল উপাদানগুলি একই ক্রমে থাকবে বলে আশা করে। অভিধান বর্গ গণনা করার সময় কী বা মানগুলির ক্রমর গ্যারান্টি দেয় না, সুতরাং আপনি যদি সিকোয়েন্সএকুয়াল ব্যবহার করতে চলেছেন তবে আপনাকে। কী এবং .Values ​​প্রথমে বাছাই করতে হবে!
অরিয়ন এডওয়ার্ডস 20

3
@ ওরিওন: ... যদি না আপনি অর্ডিং পার্থক্যগুলি সনাক্ত করতে চান তবে অবশ্যই :-)
schoetbi

30
@ এসকোয়েতবি: আপনি কেন এমন ধারকটিতে অর্ডারের পার্থক্য সনাক্ত করতে চান যা আদেশের গ্যারান্টি দেয় না ?
ম্যাটি ভির্ককুনেন

4
@ সাকোয়েতবি: এটি একটি মূল উপাদানকে একটি নির্দিষ্ট পরিমাণের বাইরে নিয়ে যাওয়ার জন্য। যাইহোক, একটি অভিধান, না গ্যারান্টি অর্ডার করে, যাতে .Keysএবং .Valuesকোনো আদেশ তারা মত মনে মধ্যে কী ও মান আসতে পারে, এবং অভিধান পাশাপাশি রুপান্তরিত করা হয়েছে, যাতে পরিবর্তন করার সম্ভাবনা রয়েছে। আমি আপনাকে একটি অভিধান কী এবং কোনটি নয় তা পড়তে পরামর্শ দিয়েছি।
ম্যাটি ভির্ককুনেন

5
এমএস 'টেস্টটুলস এবং নুনিট সংগ্রহশালা সরবরাহ করে
.আরএকুইভ্যালেন্ট

44

অন্যরা যেমন পরামর্শ ও নোট করেছে, SequenceEqualতা অর্ডার-সংবেদনশীল। এটি সমাধানের জন্য, আপনি কীটি দ্বারা অভিধানটি বাছাই করতে পারেন (যা স্বতন্ত্র, এবং এইভাবে বাছাই সর্বদা স্থিতিশীল থাকে) এবং তারপরে ব্যবহার করুন SequenceEqual। নিম্নোক্ত অভিব্যক্তিটি দুটি অভ্যন্তরীণ ক্রম নির্বিশেষে সমান কিনা তা পরীক্ষা করে:

dictionary1.OrderBy(kvp => kvp.Key).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key))

সম্পাদনা: জেপে স্টিগ নীলসনের নির্দেশ অনুসারে, কিছু কিছু বস্তুর একটি IComparer<T>অসামঞ্জস্যপূর্ণ রয়েছে IEqualityComparer<T>যা ভুল ফলাফল দেয় results এই জাতীয় কোনও অবজেক্টের সাথে কীগুলি ব্যবহার করার সময় আপনাকে অবশ্যই IComparer<T>এই কীগুলির জন্য একটি নির্দিষ্ট নির্দিষ্ট করতে হবে । উদাহরণস্বরূপ, স্ট্রিং কী (যা এই সমস্যাটি দেখায়) সহ, সঠিক ফলাফল পেতে আপনাকে অবশ্যই নিম্নলিখিত কাজগুলি করতে হবে:

dictionary1.OrderBy(kvp => kvp.Key, StringComparer.Ordinal).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key, StringComparer.Ordinal))

কী টাইপ না হলে কি হবে CompareTo? আপনার সমাধানটি তখন বিস্ফোরিত হবে। কী টাইপটির একটি ডিফল্ট তুলনামূলক থাকে যা তার ডিফল্ট সমতা তুলনার সাথে অসম্পূর্ণ? এটি ক্ষেত্রে string, আপনি জানেন। উদাহরণস্বরূপ এই অভিধানগুলি (অন্তর্নিহিত পূর্বনির্ধারিত সমতা তুলনাকারীদের সাথে) আপনার পরীক্ষায় ব্যর্থ হবে (সমস্ত সংস্কৃতির ইনফোসের অধীনে আমি সচেতন):var dictionary1 = new Dictionary<string, int> { { "Strasse", 10 }, { "Straße", 20 }, }; var dictionary2 = new Dictionary<string, int> { { "Straße", 20 }, { "Strasse", 10 }, };
জেপ্পে স্টিগ নিলসেন

@JeppeStigNielsen: মধ্যে অসঙ্গতি হিসাবে IComparerএবং IEqualityComparer- আমি এই সমস্যা সম্পর্কে সচেতন ছিল না, খুব আকর্ষণীয়! আমি উত্তরটি একটি সম্ভাব্য সমাধান সহ আপডেট করেছি। অভাব সম্পর্কে CompareTo, আমি মনে করি যে বিকাশকারীকে নিশ্চিত করা উচিত যে OrderBy()পদ্ধতিতে সরবরাহ করা প্রতিনিধি তুলনামূলক কিছু প্রত্যাবর্তন করে। আমি মনে করি এটি কোনও ব্যবহারের জন্য OrderBy(), এমনকি অভিধান তুলনার বাইরেও সত্য ।
অ্যালন গুরালেক

15

উল্লিখিত সিকোয়েন্সএকুয়াল ছাড়াও , যা

সত্য যদি দুটি তালিকাগুলি সমান দৈর্ঘ্যের হয় এবং তার সাথে সম্পর্কিত উপাদানগুলি একটি তুলনামূলক অনুসারে সমান তুলনা করে

(যা ডিফল্ট তুলনামূলক, যেমন একটি ওভারডেন হতে পারে Equals())

এটি উল্লেখ করার মতো যে। নেট 4ISetঅবজেক্টগুলিতে সেটএকুইলস রয়েছে , যা

উপাদানগুলির ক্রম এবং কোনও সদৃশ উপাদান উপেক্ষা করে।

সুতরাং যদি আপনি অবজেক্টের একটি তালিকা রাখতে চান তবে সেগুলি নির্দিষ্ট ক্রমে থাকার দরকার নেই, বিবেচনা করুন যে কোনও ISet(যেমন একটি HashSet) সঠিক পছন্দ হতে পারে।


7

কটাক্ষপাত Enumerable.SequenceEqual পদ্ধতি

var dictionary = new Dictionary<int, string>() {{1, "a"}, {2, "b"}};
var intList = new List<int> {1, 2};
var stringList = new List<string> {"a", "b"};
var test1 = dictionary.Keys.SequenceEqual(intList);
var test2 = dictionary.Values.SequenceEqual(stringList);

13
এটি নির্ভরযোগ্য নয় কারণ সিকোয়েন্সএকুয়াল একটি নির্ভরযোগ্য ক্রমে অভিধান থেকে মানগুলি বেরিয়ে আসার প্রত্যাশা করে - অভিধানটি অর্ডার সম্পর্কে কোনও গ্যারান্টি দেয় না, কীগুলি [1, 2] এর পরিবর্তে [2, 1] হিসাবে আসতে পারে could এবং আপনার পরীক্ষাটি ব্যর্থ হবে
অরিওন এডওয়ার্ডস

5

.NET সংগ্রহের তুলনা করার জন্য কোনও শক্তিশালী সরঞ্জামের অভাব রয়েছে। আমি একটি সহজ সমাধান বিকাশ করেছি যা আপনি নীচের লিঙ্কটিতে খুঁজে পেতে পারেন:

http://robertbouillon.com/2010/04/29/comparing-collections-in-net/

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

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

10
অবশ্যই .NET এর সাথে তুলনা করার জন্য শক্তিশালী সরঞ্জাম রয়েছে (সেগুলি সেট-ভিত্তিক ক্রিয়াকলাপ)। .Removedহিসাবে একই list1.Except(list2), .Addedহয় list2.Except(list1), .Equalহয় list1.Intersect(list2)এবং .Differentহয় original.Join(changed, left => left.Key, right => right.Key, (left, right) => left.Value == right.Value)। আপনি লিনকিউয়ের সাথে প্রায় কোনও তুলনা করতে পারেন।
অ্যালন গুরালেনেক

3
সংশোধন: .Differentহয় original.Join(changed, left => left.Key, right => right.Key, (left, right) => new { Key = left.Key, NewValue = right.Value, Different = left.Value == right.Value).Where(d => d.Different)। আপনি এমনকি OldValue = left.Valueপুরানো মান প্রয়োজন হলে আপনি যোগ করতে পারেন ।
অ্যালন গুরালেনেক

3
@ অ্যালন গুরালেক আপনার পরামর্শগুলি ভাল, তবে তালিকাটি সত্যিকারের সেট নয় - যেখানে তালিকায় একই বস্তুটি একাধিকবার উপস্থিত থাকে সেগুলি তারা পরিচালনা করে না। {1, 2} এবং {1, 2, 2 Comp তুলনা করলে কিছুই যোগ / সরানো হবে না।
নিলাল কানাহটন


4

আমি Enumerable.SequenceEqual পদ্ধতি সম্পর্কে জানতাম না (আপনি প্রতিদিন কিছু শিখেন ....), তবে আমি একটি এক্সটেনশন পদ্ধতি ব্যবহার করার পরামর্শ দিচ্ছিলাম; এটার মতো কিছু:

    public static bool IsEqual(this List<int> InternalList, List<int> ExternalList)
    {
        if (InternalList.Count != ExternalList.Count)
        {
            return false;
        }
        else
        {
            for (int i = 0; i < InternalList.Count; i++)
            {
                if (InternalList[i] != ExternalList[i])
                    return false;
            }
        }

        return true;

    }

মজার বিষয় যথেষ্ট, সিকোয়েন্সএকুয়াল সম্পর্কে পড়তে 2 সেকেন্ড সময় নেওয়ার পরেও দেখে মনে হচ্ছে যে মাইক্রোসফ্ট আমি আপনার জন্য বর্ণিত ফাংশনটি তৈরি করেছি।


4

এটি সরাসরি আপনার প্রশ্নের উত্তর দিচ্ছে না, তবে এমএসের টেস্টটুলস এবং নুনিট উভয়ই সরবরাহ করে

 CollectionAssert.AreEquivalent

যা আপনি যা চান তা বেশ কার্যকর করে।


আমার
ইউনাইট

1

সংগ্রহগুলি তুলনা করতে আপনি লিনকিউ ব্যবহার করতে পারেন। Enumerable.Intersectসমান যে সমস্ত জোড়া প্রদান। আপনি এর মতো দুটি অভিধান তুলনা করতে পারেন:

(dict1.Count == dict2.Count) && dict1.Intersect(dict2).Count() == dict1.Count

প্রথম তুলনাটি প্রয়োজন কারণ dict2সমস্ত কি dict1এবং আরও বেশি কিছু থাকতে পারে ।

আপনি ব্যবহার করে বিভিন্নতার কথা চিন্তা করতে পারেন Enumerable.Exceptএবং Enumerable.Unionএটি একইরকম ফলাফলের দিকে নিয়ে যায়। তবে সেটগুলির মধ্যে সঠিক পার্থক্য নির্ধারণ করতে ব্যবহার করা যেতে পারে।


1

এই উদাহরণটি সম্পর্কে:

 static void Main()
{
    // Create a dictionary and add several elements to it.
    var dict = new Dictionary<string, int>();
    dict.Add("cat", 2);
    dict.Add("dog", 3);
    dict.Add("x", 4);

    // Create another dictionary.
    var dict2 = new Dictionary<string, int>();
    dict2.Add("cat", 2);
    dict2.Add("dog", 3);
    dict2.Add("x", 4);

    // Test for equality.
    bool equal = false;
    if (dict.Count == dict2.Count) // Require equal count.
    {
        equal = true;
        foreach (var pair in dict)
        {
            int value;
            if (dict2.TryGetValue(pair.Key, out value))
            {
                // Require value be equal.
                if (value != pair.Value)
                {
                    equal = false;
                    break;
                }
            }
            else
            {
                // Require key be present.
                equal = false;
                break;
            }
        }
    }
    Console.WriteLine(equal);
}

সৌজন্যে: https://www.dotnetperls.com / অভিধান / মানের


মান! = জোড়া।ভ্যালু রেফারেন্স তুলনা করছে, পরিবর্তে সমান ব্যবহার করুন
কোফিফাস

1

অর্ডার করা সংগ্রহের জন্য (তালিকা, অ্যারে) ব্যবহারের জন্য SequenceEqual

হ্যাশসেট ব্যবহারের জন্য SetEquals

অভিধানের জন্য আপনি করতে পারেন:

namespace System.Collections.Generic {
  public static class ExtensionMethods {
    public static bool DictionaryEquals<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> d1, IReadOnlyDictionary<TKey, TValue> d2) {
      if (object.ReferenceEquals(d1, d2)) return true; 
      if (d2 is null || d1.Count != d2.Count) return false;
      foreach (var (d1key, d1value) in d1) {
        if (!d2.TryGetValue(d1key, out TValue d2value)) return false;
        if (!d1value.Equals(d2value)) return false;
      }
      return true;
    }
  }
}

(একটি আরও অনুকূলিত সমাধান সমাধান বাছাই ব্যবহার করবে তবে এটির প্রয়োজন হবে IComparable<TValue>)


0

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


0

না, কারণ ফ্রেমওয়ার্কটি কীভাবে আপনার তালিকাগুলির সামগ্রীগুলি তুলনা করতে পারে তা জানে না।

এটি একবার দেখুন:

http://blogs.msdn.com/abhinaba/archive/2005/10/11/479537.aspx


3
উপাদানগুলি কীভাবে তুলনা করবেন তা কাঠামোটি বলার জন্য ইতিমধ্যে বেশ কয়েকটি বিকল্প নেই? IComparer<T>, ওভার-রাইড object.Equals, IEquatable<T>, IComparable<T>...
স্টিফান Steinegger

0
public bool CompareStringLists(List<string> list1, List<string> list2)
{
    if (list1.Count != list2.Count) return false;

    foreach(string item in list1)
    {
        if (!list2.Contains(item)) return false;
    }

    return true;
}

0

সেখানে ছিল না, নেই এবং নাও হতে পারে, অন্তত আমি এটি বিশ্বাস করব। সংগ্রহ সমতার পিছনে কারণ সম্ভবত কোনও ব্যবহারকারী সংজ্ঞায়িত আচরণ।

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

{1, 2, 3, 4}
{4, 3, 2, 1}

তারা সমান না কি? আপনার অবশ্যই জানা উচিত তবে আপনার দৃষ্টিভঙ্গি কী তা আমি জানি না।

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

https://docs.microsoft.com/en-US/sql/t-sql/queries/select-order-by-clause-transact-sql?view=sql-server-2017

আরও দুটি সংগ্রহ:

{1, 2, 3, 4}
{1, 1, 1, 2, 2, 3, 4}

আবার, তারা কি সমান বা না? তুমি আমাকে বলো ..

কোনও সংকলনের উপাদান পুনরাবৃত্তিযোগ্যতা বিভিন্ন পরিস্থিতিতে তার ভূমিকা পালন করে এবং কিছু সংকলন Dictionary<TKey, TValue>এমনকি পুনরাবৃত্ত উপাদানগুলিকে মঞ্জুরি দেয় না।

আমি বিশ্বাস করি যে এই ধরণের সাম্যতা হ'ল অ্যাপ্লিকেশন সংজ্ঞায়িত এবং ফলে কাঠামোগুলি সম্ভাব্য বাস্তবায়নগুলির সমস্ত সরবরাহ করে না।

ভাল, সাধারণ ক্ষেত্রে Enumerable.SequenceEqualযথেষ্ট ভাল তবে এটি নিম্নলিখিত ক্ষেত্রে মিথ্যা ফিরিয়ে দেয়:

var a = new Dictionary<String, int> { { "2", 2 }, { "1", 1 }, };
var b = new Dictionary<String, int> { { "1", 1 }, { "2", 2 }, };
Debug.Print("{0}", a.SequenceEqual(b)); // false

আমি এই জাতীয় প্রশ্নের কিছু উত্তর পড়েছি (আপনি তাদের জন্য গুগল করতে পারেন ) এবং আমি কী ব্যবহার করব তা সাধারণভাবে:

public static class CollectionExtensions {
    public static bool Represents<T>(this IEnumerable<T> first, IEnumerable<T> second) {
        if(object.ReferenceEquals(first, second)) {
            return true;
        }

        if(first is IOrderedEnumerable<T> && second is IOrderedEnumerable<T>) {
            return Enumerable.SequenceEqual(first, second);
        }

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

        first=first.OrderBy(x => x.GetHashCode());
        second=second.OrderBy(x => x.GetHashCode());
        return CollectionExtensions.Represents(first, second);
    }
}

এর অর্থ একটি আসল মূল ক্রমটিকে বিবেচনায় না নিয়ে বারবার বার সহ তাদের উপাদানগুলিতে অন্যটির প্রতিনিধিত্ব করে। বাস্তবায়নের কয়েকটি নোট:

  • GetHashCode()সাম্যের জন্য নয় কেবল আদেশের জন্য; আমি মনে করি এটি এক্ষেত্রে যথেষ্ট

  • Count() প্রকৃতপক্ষে সংগ্রহটি গণনা করবে না এবং সরাসরি সম্পত্তি প্রয়োগের মধ্যে পড়বে ICollection<T>.Count

  • যদি রেফারেন্সগুলি সমান হয় তবে এটি কেবল বরিস

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