একটি তালিকায় আইটেমগুলি পেতে লিনকিউ ব্যবহার করুন <>, অন্য তালিকায় নেই <>


524

আমি ধরে নেব এটি করার জন্য একটি সাধারণ লিনকিউ কোয়েরি আছে, আমি ঠিক কীভাবে তা নিশ্চিত নই।

এই কোডটি দেওয়া হয়েছে:

class Program
{
    static void Main(string[] args)
    {
        List<Person> peopleList1 = new List<Person>();
        peopleList1.Add(new Person() { ID = 1 });
        peopleList1.Add(new Person() { ID = 2 });
        peopleList1.Add(new Person() { ID = 3 });

        List<Person> peopleList2 = new List<Person>();
        peopleList2.Add(new Person() { ID = 1 });
        peopleList2.Add(new Person() { ID = 2 });
        peopleList2.Add(new Person() { ID = 3 });
        peopleList2.Add(new Person() { ID = 4 });
        peopleList2.Add(new Person() { ID = 5 });
    }
}

class Person
{
    public int ID { get; set; }
}

আমি একটি LINQ ক্যোয়ারীর কার্য সম্পাদনা করার জন্য আমাকে সব মানুষের মধ্যেই দিতে চাই peopleList2যে নেই peopleList1

এই উদাহরণে আমাকে দু'জন লোক দেওয়া উচিত (আইডি = 4 এবং আইডি = 5)


3
আইডিটি কেবলমাত্র পঠনযোগ্যভাবে তৈরি করা ভাল ধারণা যেহেতু কোনও সামগ্রীর সনাক্তকরণ তার লাইভ সময়ের সাথে পরিবর্তন করা উচিত নয়। অবশ্যই আপনার পরীক্ষার- বা ORM- কাঠামোর জন্য এটি পরিবর্তনীয় হতে হবে।
CodeInChaos

উত্তর:


910

নিম্নলিখিত লিনকিউ এক্সপ্রেশন ব্যবহার করে এটি সম্বোধন করা যেতে পারে:

var result = peopleList2.Where(p => !peopleList1.Any(p2 => p2.ID == p.ID));

এটি লিনকিউ এর মাধ্যমে প্রকাশ করার একটি বিকল্প উপায়, যা কিছু বিকাশকারী আরও পাঠযোগ্য বলে মনে করে:

var result = peopleList2.Where(p => peopleList1.All(p2 => p2.ID != p.ID));

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


34
আপনি সচেতন যে এটি কোনও ও (এন * মি) এর সমাধান যা ও (এন + মি) সময়ে সহজেই সমাধান করা যায়?
নিকি 18

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

46
@ নিকি, আপনার সহজ সমাধানটি ভাগ করে দেওয়ার জন্য যত্নশীল?
রুবিও

18
এটি সমতুল্য এবং আমি অনুসরণ করতে আরও সহজ খুঁজে পেয়েছি: var ফলাফল = লোকলিস্ট 2 W যেখানে (পি => লোকলিস্ট 1 ll সমস্ত (পি 2 => পি 2.আইডি! = পি.আইডি));
আন্তোনকে

28
@ মেনল - যে কোনও প্রশ্নের সঠিকভাবে প্রতিক্রিয়া জানিয়েছেন এমন কারও সমালোচনা করা কিছুটা অন্যায় হতে পারে। ভবিষ্যতে লোকেরা যে উত্তরটি নিয়ে যেতে পারে তার সমস্ত উপায় এবং প্রেক্ষাপট সম্পর্কে লোকেরা অনুমান করার দরকার নেই। বাস্তবে, আপনার এটি নিকি-তে নির্দেশ করা উচিত - যারা সময় দেওয়ার সময় বলেছিলেন যে তারা সরবরাহ না করেই বিকল্প সম্পর্কে জানেন।
ক্রিস রজার্স

395

আপনি যদি মানুষের সাম্যাকে ওভাররাইড করেন তবে আপনি এটিও ব্যবহার করতে পারেন:

peopleList2.Except(peopleList1)

ExceptWhere(...Any)বৈকল্পিকের তুলনায় উল্লেখযোগ্যভাবে দ্রুত হওয়া উচিত কারণ এটি দ্বিতীয় তালিকাকে হ্যাশটেবলে রাখতে পারে। Where(...Any)একটি রানটাইম হয়েছে O(peopleList1.Count * peopleList2.Count)যেহেতু উপর ভিত্তি করে রূপগুলো HashSet<T>(প্রায়) একটি রানটাইম আছে O(peopleList1.Count + peopleList2.Count)

Exceptস্পষ্টতই সদৃশগুলি মুছে ফেলুন। এটি আপনার কেসকে প্রভাবিত করবে না, তবে একই ধরনের ক্ষেত্রে এটি একটি সমস্যা হতে পারে।

অথবা আপনি যদি দ্রুত কোড চান তবে সমতাটি ওভাররাইড করতে চান না:

var excludedIDs = new HashSet<int>(peopleList1.Select(p => p.ID));
var result = peopleList2.Where(p => !excludedIDs.Contains(p.ID));

এই রূপটি সদৃশগুলি সরায় না।


Equalsআইডি এর তুলনা করতে ওভাররাইড করা থাকলে এটি কেবল কাজ করবে ।
ক্লাউস বাইস্কোভ পেডারসেন

34
সে কারণেই আমি লিখেছি যে আপনার সাম্যকে ওভাররাইড করা উচিত। তবে আমি একটি উদাহরণ যুক্ত করেছি যা এটি ছাড়াও কার্যকর হয়।
কোডসইনচওস

4
ব্যক্তি কাঠামো হলে এটিও কাজ করবে। যদিও এটি যেমন, ব্যক্তি একটি অসম্পূর্ণ বর্গ বলে মনে হচ্ছে কারণ এর "আইডি" নামক একটি সম্পত্তি রয়েছে যা এটি সনাক্ত করে না - যদি এটি সনাক্ত করে, তবে সমান আইডিটি সমান ব্যক্তি হিসাবে বোঝানো হবে over পার্সনে থাকা বাগটি ঠিক হয়ে গেলে, এই পদ্ধতির পরে আরও ভাল (যদি বাগ সনাক্তকারী হিসাবে মনে করে ভুল পথে চালিত না হয় এমন কোনও কিছুতে "আইডি" নাম পরিবর্তন করে স্থির না করা হয়)।
জন হান্না

2
আপনি যদি স্ট্রিংগুলির একটি তালিকা (বা অন্যান্য বেস অবজেক্টস) সম্পর্কে কথা বলছেন তবে এটি দুর্দান্ত কাজ করে, যা আমি এই থ্রেডটিতে আসার সময় সন্ধান করছিলাম।
ড্যান কর্ন

@ ড্যানকর্ন সেম, এটি তুলনামূলকভাবে, মৌলিক তুলনার জন্য, int, অবজেক্টস রেফ, স্ট্রিংয়ের তুলনায় এটি একটি সহজ সমাধান।
গোলকধাঁধা

73

অথবা আপনি যদি তা অস্বীকার না করে চান:

var result = peopleList2.Where(p => peopleList1.All(p2 => p2.ID != p.ID));

মূলত এটি জনগণের কাছ থেকে সমস্ত কিছু পান বলে তালিকা 2 যেখানে লোকাললিস্ট 1 এ সমস্ত আইডি পিপলসলিস্ট 2 এর আইডি থেকে আলাদা।

গৃহীত উত্তর থেকে কিছুটা আলাদা পদ্ধতির :)


5
এই পদ্ধতিটি (50,000 এরও বেশি আইটেমের তালিকা) যে কোনও পদ্ধতির চেয়ে উল্লেখযোগ্যভাবে দ্রুত ছিল!
ডেভন

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

32

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

var peopleDifference = 
  from person2 in peopleList2
  where !(
      from person1 in peopleList1 
      select person1.ID
    ).Contains(person2.ID)
  select person2;

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


ধন্যবাদ. ক্যোয়ারী এক্সপ্রেশন সিনট্যাক্স নিয়ে বিরক্ত হওয়া প্রথম উত্তর।
জেনেরিক নাম

15

পার্টিতে দেরি হয়ে গেলেও লিনাক থেকে এসকিউএল সামঞ্জস্যপূর্ণ একটি ভাল সমাধান হ'ল:

List<string> list1 = new List<string>() { "1", "2", "3" };
List<string> list2 = new List<string>() { "2", "4" };

List<string> inList1ButNotList2 = (from o in list1
                                   join p in list2 on o equals p into t
                                   from od in t.DefaultIfEmpty()
                                   where od == null
                                   select o).ToList<string>();

List<string> inList2ButNotList1 = (from o in list2
                                   join p in list1 on o equals p into t
                                   from od in t.DefaultIfEmpty()
                                   where od == null
                                   select o).ToList<string>();

List<string> inBoth = (from o in list1
                       join p in list2 on o equals p into t
                       from od in t.DefaultIfEmpty()
                       where od != null
                       select od).ToList<string>();

Http://www.dotnet-tricks.com/ টিউটোরিয়াল / লিংক / ইউএক্সপিএফ 181012- এসকিউএল- যোগ- সাথে- সি-তে কুদোস


12

ক্লাউসের উত্তর দুর্দান্ত ছিল, তবে রিশার্পার আপনাকে "লিনকিউ এক্সপ্রেশনকে সরলকরণ" করতে বলবে:

var result = peopleList2.Where(p => peopleList1.All(p2 => p2.ID != p.ID));


এটি লক্ষণীয় যে এই কৌশলটি কাজ করবে না যদি সেখানে দুটি বস্তুকে একের অধিক সম্পত্তি আবদ্ধ করা হয় (মনে করুন এসকিউএল সম্মিলিত কী)।
Alrekr

Alrekr - আপনি যা বলতে চাইছেন তা যদি "আরও বেশি সংখ্যার সাথে তুলনা করার প্রয়োজন হয় তবে আপনাকে আরও সম্পত্তিগুলির তুলনা করতে হবে" তবে আমি বলব এটি বেশ সুস্পষ্ট।
লুকাস মরগান

8

এই গণনাযোগ্য এক্সটেনশন আপনাকে বাদ দিতে আইটেমের একটি তালিকা এবং তুলনা সম্পাদন করতে কী ব্যবহার করার জন্য কী ব্যবহার করতে কোনও ফাংশন সংজ্ঞায়িত করতে দেয়।

public static class EnumerableExtensions
{
    public static IEnumerable<TSource> Exclude<TSource, TKey>(this IEnumerable<TSource> source,
    IEnumerable<TSource> exclude, Func<TSource, TKey> keySelector)
    {
       var excludedSet = new HashSet<TKey>(exclude.Select(keySelector));
       return source.Where(item => !excludedSet.Contains(keySelector(item)));
    }
}

আপনি এটি এভাবে ব্যবহার করতে পারেন

list1.Exclude(list2, i => i.ID);

@ ব্রায়ানটি-র কোডটি পেয়ে আমি কীভাবে এটি আপনার কোডটি ব্যবহার করতে রূপান্তর করতে পারি?
নিক ম্যানারিন

0

এখানে একটি কাজের উদাহরণ যা আইটি দক্ষতা পান যা কোনও চাকরি প্রার্থী ইতিমধ্যে নেই।

//Get a list of skills from the Skill table
IEnumerable<Skill> skillenum = skillrepository.Skill;
//Get a list of skills the candidate has                   
IEnumerable<CandSkill> candskillenum = candskillrepository.CandSkill
       .Where(p => p.Candidate_ID == Candidate_ID);             
//Using the enum lists with LINQ filter out the skills not in the candidate skill list
IEnumerable<Skill> skillenumresult = skillenum.Where(p => !candskillenum.Any(p2 => p2.Skill_ID == p.Skill_ID));
//Assign the selectable list to a viewBag
ViewBag.SelSkills = new SelectList(skillenumresult, "Skill_ID", "Skill_Name", 1);

0

প্রথমে সংগ্রহের শর্ত থেকে আইডি বের করুন

List<int> indexes_Yes = this.Contenido.Where(x => x.key == 'TEST').Select(x => x.Id).ToList();

দ্বিতীয়ত, নির্বাচনের থেকে পৃথক আইডি নির্বাচন করতে "তুলনা করুন" সম্পদ ব্যবহার করুন

List<int> indexes_No = this.Contenido.Where(x => !indexes_Yes.Contains(x.Id)).Select(x => x.Id).ToList();

স্পষ্টতই আপনি x.key! = "TEST" ব্যবহার করতে পারেন তবে এটি একটি উদাহরণ


0

একবার আপনি জেনেরিক FuncEqualityComparer লিখলে আপনি এটিকে যে কোনও জায়গায় ব্যবহার করতে পারবেন।

peopleList2.Except(peopleList1, new FuncEqualityComparer<Person>((p, q) => p.ID == q.ID));

public class FuncEqualityComparer<T> : IEqualityComparer<T>
{
    private readonly Func<T, T, bool> comparer;
    private readonly Func<T, int> hash;

    public FuncEqualityComparer(Func<T, T, bool> comparer)
    {
        this.comparer = comparer;
        if (typeof(T).GetMethod(nameof(object.GetHashCode)).DeclaringType == typeof(object))
            hash = (_) => 0;
        else
            hash = t => t.GetHashCode(); 
    }

    public bool Equals(T x, T y) => comparer(x, y);
    public int GetHashCode(T obj) => hash(obj);
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.