পার্থক্যের জন্য দুটি জেনেরিক তালিকার দ্রুততম উপায়


214

দুটি বৃহত্তর (> 50.000 আইটেম) তুলনা করার দ্রুত (এবং সর্বনিম্ন সংস্থান নিবিড়) কী এবং ফলস্বরূপ নীচেরগুলির মতো দুটি তালিকা রয়েছে:

  1. প্রথম তালিকায় প্রদর্শিত আইটেমগুলি কিন্তু দ্বিতীয়টিতে নয়
  2. দ্বিতীয় তালিকায় প্রদর্শিত আইটেমগুলি কিন্তু প্রথমটিতে নয়

বর্তমানে আমি তালিকা বা IReadOnly সংগ্রহের সাথে কাজ করছি এবং একটি লিনিক ক্যোয়ারিতে এই সমস্যাটি সমাধান করুন:

var list1 = list.Where(i => !list2.Contains(i)).ToList();
var list2 = list2.Where(i => !list.Contains(i)).ToList();

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

উত্তর:


454

ব্যবহার Except:

var firstNotSecond = list1.Except(list2).ToList();
var secondNotFirst = list2.Except(list1).ToList();

আমি সন্দেহ সেখানে পন্থা যা আসলে সীমিতভাবে দ্রুত এই তুলনায় হবে, কিন্তু এমনকি এই হতে হবে অতি দ্রুত আপনার হে (ঢ * এম) পদ্ধতির চেয়ে।

আপনি যদি এগুলি একত্রিত করতে চান তবে উপরেরটি দিয়ে একটি পদ্ধতি তৈরি করতে পারেন এবং তারপরে একটি রিটার্ন বিবৃতি:

return !firstNotSecond.Any() && !secondNotFirst.Any();

নোট এক বিন্দু সেখানে যে হয় প্রশ্নে মূল কোড এবং সমাধান এখানে মধ্যে ফলাফলে একটি পার্থক্য: কোন সদৃশ উপাদান যা শুধুমাত্র একটি তালিকায় কেবল যেহেতু তারা অনেক হিসাবে প্রতিবেদন অনুভব করি, আমার কোড একবার রিপোর্ট করা হবে তারা মূল কোড হিসাবে ঘটবে হিসাবে বার।

উদাহরণস্বরূপ, তালিকা [1, 2, 2, 2, 3]এবং এর সাথে [1], " তালিকায় থাকা উপাদানগুলিতে তবে তালিকা 2 নয়" মূল কোডে ফলাফল হবে [2, 2, 2, 3]। আমার কোড সহ এটি ঠিক হবে [2, 3]। অনেক ক্ষেত্রেই এটি কোনও সমস্যা হবে না তবে এটি সম্পর্কে সচেতন হওয়া মূল্যবান।


8
এটি সত্যিই একটি বিশাল পারফরম্যান্স লাভ! এই উত্তরের জন্য ধন্যবাদ।
ফ্র্যাঙ্ক

2
আমি দুটি বিশাল তালিকার জন্য ভাবছি, তুলনার আগে বাছাই করা কি কার্যকর? বা এক্সটেনশান পদ্ধতি বাদে, পাস করা তালিকাটি ইতিমধ্যে বাছাই করা আছে।
ল্যারি

9
@ ল্যারি: এটি বাছাই করা হয়নি; এটি একটি হ্যাশ সেট তৈরি করে।
জন স্কিটি

2
@ প্রণবসিংহ: এটি যথাযথ সাম্য আছে এমন কোনও কিছুর জন্য কাজ করবে - সুতরাং যদি আপনার কাস্টম টাইপটি ওভাররাইড করে Equals(object)এবং / বা প্রয়োগ করে তবে IEquatable<T>তা ঠিক করা উচিত।
জন স্কিটি

2
@ k2ibegin: এটি ডিফল্ট সমতা তুলনামূলক ব্যবহার করে, যা একটি IEquatable<T>বাস্তবায়ন বা object.Equals(object)পদ্ধতি ব্যবহার করবে । মনে হচ্ছে আপনার একটি ন্যূনতম প্রজননযোগ্য উদাহরণ সহ একটি নতুন প্রশ্ন তৈরি করা উচিত - আমরা মন্তব্যগুলিতে জিনিসগুলি সত্যই নির্ণয় করতে পারি না।
জন স্কিটি

40

আরও দক্ষ ব্যবহার করা হবে Enumerable.Except:

var inListButNotInList2 = list.Except(list2);
var inList2ButNotInList = list2.Except(list);

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

var first10 = inListButNotInList2.Take(10);

এটি অভ্যন্তরীণভাবে Set<T>অবজেক্টগুলির সাথে তুলনা করতে ব্যবহার করে এটি কার্যকর efficient এটি প্রথম দ্বিতীয় ক্রম থেকে সমস্ত স্বতন্ত্র মান সংগ্রহ করে এবং তারপরে প্রথমটির ফলাফলগুলি স্ট্রিম করে কাজ করে যা তারা আগে দেখা যায় নি checking


1
হুম। বেশ পিছিয়ে নেই। আমি বলতে চাই আংশিক স্থগিত। একটি সম্পূর্ণ Set<T>দ্বিতীয় ক্রম (যেমন এটি সম্পূর্ণ পুনরাবৃত্তি এবং সঞ্চিত) থেকে তৈরি করা হয়, তারপরে প্রথম ক্রম থেকে যুক্ত করা যায় এমন আইটেম পাওয়া যায়।
ব্যয়কারী

2
@ স্পেন্ডার, এটি বলার মতো যে মৃত্যুদন্ড কার্যকর Whereকরা আংশিক স্থগিত করা হয় কারণ list.Where(x => x.Id == 5)সংখ্যাটির মূল্যে 5অলসভাবে মৃত্যুদণ্ড কার্যকর করার পরিবর্তে শুরুতে সংরক্ষণ করা হয়।
jwg

27

গুণনীয়

সমতা তুলক অনুসারে দুটি ক্রম সমান কিনা তা নির্ধারণ করে। MS.Docs

Enumerable.SequenceEqual(list1, list2);

এটি সমস্ত আদিম ডেটা ধরণের জন্য কাজ করে। আপনার যদি কাস্টম অবজেক্টে এটি ব্যবহার করতে হয় তবে আপনার প্রয়োগ করতে হবেIEqualityComparer

সাম্যের জন্য বস্তুর তুলনা সমর্থন করার জন্য পদ্ধতিগুলি সংজ্ঞায়িত করে।

আইকুয়ালিটিকম্পার ইন্টারফেস

সাম্যের জন্য বস্তুর তুলনা সমর্থন করার জন্য পদ্ধতিগুলি সংজ্ঞায়িত করে। আই.কোয়ালিটি কম্পিউটারের জন্য এমএস ডকস oc


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

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

হ্যাঁ, সঠিক, দেখে মনে হচ্ছে যে আমি
এটির

9

আপনি যদি ফলাফলগুলি সংবেদনশীল হতে চান তবে নিম্নলিখিতগুলি কাজ করবে:

List<string> list1 = new List<string> { "a.dll", "b1.dll" };
List<string> list2 = new List<string> { "A.dll", "b2.dll" };

var firstNotSecond = list1.Except(list2, StringComparer.OrdinalIgnoreCase).ToList();
var secondNotFirst = list2.Except(list1, StringComparer.OrdinalIgnoreCase).ToList();

firstNotSecondধারণ করবে b1.dll

secondNotFirstb2.dll ধারণ করবে


5

এই সমস্যার জন্য নয়, তবে সমান জন্য তালিকার তুলনা করার জন্য এখানে কিছু কোড রয়েছে এবং না! অভিন্ন বস্তু:

public class EquatableList<T> : List<T>, IEquatable<EquatableList<T>> where    T : IEquatable<T>

/// <summary>
/// True, if this contains element with equal property-values
/// </summary>
/// <param name="element">element of Type T</param>
/// <returns>True, if this contains element</returns>
public new Boolean Contains(T element)
{
    return this.Any(t => t.Equals(element));
}

/// <summary>
/// True, if list is equal to this
/// </summary>
/// <param name="list">list</param>
/// <returns>True, if instance equals list</returns>
public Boolean Equals(EquatableList<T> list)
{
    if (list == null) return false;
    return this.All(list.Contains) && list.All(this.Contains);
}

1
কাস্টম ডেটা ধরণের তুলনা করতে আপনার এটির দরকার। তারপরে ব্যবহার করুনExcept
প্রণব সিং

আপনি সম্ভবত বাছাইযোগ্য প্রকারের সাথে আরও ভাল করতে পারেন। এটি O (n ^ 2) এ চলে, আপনি O (nlogn) করতে পারবেন।
yuvalm2

3

এইভাবে চেষ্টা করুন:

var difList = list1.Where(a => !list2.Any(a1 => a1.id == a.id))
            .Union(list2.Where(a => !list1.Any(a1 => a1.id == a.id)));

13
এটি ভয়াবহ পারফরম্যান্সে ভুগছে, প্রথমটিতে প্রতিটি আইটেমের জন্য দ্বিতীয় তালিকার স্ক্যান প্রয়োজন। ডাউনভোটিং নয় কারণ এটি কাজ করে তবে এটি মূল কোডের মতোই খারাপ।
ব্যয়কারী

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

namespace YourProject.Extensions
{
    public static class ListExtensions
    {
        public static bool SetwiseEquivalentTo<T>(this List<T> list, List<T> other)
            where T: IEquatable<T>
        {
            if (list.Except(other).Any())
                return false;
            if (other.Except(list).Any())
                return false;
            return true;
        }
    }
}

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

ব্যবহার:

public sealed class Car : IEquatable<Car>
{
    public Price Price { get; }
    public List<Component> Components { get; }

    ...
    public override bool Equals(object obj)
        => obj is Car other && Equals(other);

    public bool Equals(Car other)
        => Price == other.Price
            && Components.SetwiseEquivalentTo(other.Components);

    public override int GetHashCode()
        => Components.Aggregate(
            Price.GetHashCode(),
            (code, next) => code ^ next.GetHashCode()); // Bitwise XOR
}

Componentশ্রেণি যাই হোক না কেন , এখানে দেখানো পদ্ধতিগুলি Carপ্রায় একইভাবে কার্যকর করা উচিত।

আমরা কীভাবে গেটহ্যাশকোড লিখেছি তা লক্ষ করা খুব গুরুত্বপূর্ণ। সঠিকভাবে বাস্তবায়নের লক্ষ্যে IEquatable, Equalsএবং GetHashCode উচিত একটি কথাটি সামঞ্জস্যপূর্ণ ভাবে উদাহরণস্বরূপ এর বৈশিষ্ট্য উপর কাজ করে।

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

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


1

আমি এই কোডটি দুটি তালিকার সাথে তুলনা করতে ব্যবহার করেছি যার মিলিয়ন রেকর্ড রয়েছে।

এই পদ্ধতিতে বেশি সময় লাগবে না

    //Method to compare two list of string
    private List<string> Contains(List<string> list1, List<string> list2)
    {
        List<string> result = new List<string>();

        result.AddRange(list1.Except(list2, StringComparer.OrdinalIgnoreCase));
        result.AddRange(list2.Except(list1, StringComparer.OrdinalIgnoreCase));

        return result;
    }

0

যদি কেবল সম্মিলিত ফলাফলের প্রয়োজন হয় তবে এটিও কার্যকর হবে:

var set1 = new HashSet<T>(list1);
var set2 = new HashSet<T>(list2);
var areEqual = set1.SetEquals(set2);

যেখানে টি তালিকার উপাদানগুলির টাইপ।


-1

এটি মজার হতে পারে তবে আমার পক্ষে কাজ করে

স্ট্রিং.জয়েন ("", তালিকা 1)! = স্ট্রিং.জয়াইন ("", তালিকা 2)


যেমনটি এখানে লেখা আছে এটি তালিকা <স্ট্রিং> বা তালিকা <int> এর জন্যও কাজ করবে না, উদাহরণস্বরূপ দুটি তালিকা 11; 2; 3 এবং 1; 12; 3 অভিন্ন হবে কারণ আপনি কিছুটির সাথে স্ট্রিংগুলিতে যোগদান না করে অনন্য বিভাজক যা তালিকার কোনও সম্ভাব্য আইটেম নয়। এগুলি ছাড়াও প্রচুর আইটেমের সাথে তালিকার জন্য স্ট্রিংকেট করা সম্ভবত পারফরম্যান্স হত্যাকারী।
সুইসকডার

@ সুইসকোডার: আপনি ভুল, এটি স্ট্রিংয়ের জন্য পারফরম্যান কিলার নয়। আপনার 50.000 স্ট্রিং (দৈর্ঘ্যের 3 টি) সহ দুটি তালিকা থাকলে এই অ্যালগরিদমের আমার মেশিনে 3 এমএস দরকার। স্বীকৃত উত্তরদাতাদের দরকার 7.. আমি মনে করি কৌশলটি জিবসের কেবল একটি স্ট্রিং তুলনা প্রয়োজন। অবশ্যই তাকে একটি অনন্য বিভাজক যুক্ত করতে হবে।
ব্যবহারকারী 1027167

@ ব্যবহারকারী 1027167: আমি সরাসরি স্ট্রিংগুলির তুলনা করার বিষয়ে কথা বলছি না (কারণ এটিও প্রশ্ন নয়)। 50.000 অবজেক্টের সাথে তালিকার সমস্ত অবজেক্টের .ToString () পদ্ধতিতে কলিং এটি কার্যকরভাবে নির্ভর করে, একটি বিশাল স্ট্রিং তৈরি করতে পারে। আমার মনে হয় না এটাই চলার পথ। তারপরে কোনও চরিত্র বা স্ট্রিং "অনন্য" হওয়ার উপর নির্ভর করাও ঝুঁকিপূর্ণ, কোডটি আসলে এর মতো পুনরায় ব্যবহারযোগ্য হবে না।
সুইসকোডার

ঠিক আছে সত্য। প্রশ্নকর্তা তার তালিকাগুলির ডেটাটাইপ না দিয়ে দ্রুততম পথ চেয়েছিলেন। সম্ভবত এই উত্তরদাতাকে প্রশ্নকারীর ব্যবহারের ক্ষেত্রে দ্রুততম উপায়।
ব্যবহারকারী 1027167

-3

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

x=[1,2,3,5,4,8,7,11,12,45,96,25]
y=[2,4,5,6,8,7,88,9,6,55,44,23]

tmp = []


for i in range(len(x)) and range(len(y)):
    if x[i]>y[i]:
        tmp.append(1)
    else:
        tmp.append(0)
print(tmp)

3
এটি একটি সি # প্রশ্ন এবং আপনি সি # কোড সরবরাহ করেন নি।
ওয়াই হা লি

1
সম্ভবত আপনি এই উত্তরটি মুছতে এবং এটিকে সরিয়ে ফেলতে পারেন (উদাহরণস্বরূপ) আমি কীভাবে অজগর এবং ফিরতি ম্যাচে দুটি তালিকার তুলনা করতে পারি ?
ওয়াই হা লি

-4

এটিই আপনি খুঁজে পাবেন সেরা সমাধান

var list3 = list1.Where(l => list2.ToList().Contains(l));

1
এটি আসলে খুব খারাপ কারণ এটি List<T>প্রতিটি উপাদানের জন্য একটি নতুন তৈরি করে list1। এছাড়াও ফলাফল বলা হয় list3যখন এটি না হয় List<T>
ওয়াই হা লি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.