লিনকিউতে অবজেক্টে কাজ করা স্বতন্ত্র


120
class Program
{
    static void Main(string[] args)
    {
        List<Book> books = new List<Book> 
        {
            new Book
            {
                Name="C# in Depth",
                Authors = new List<Author>
                {
                    new Author 
                    {
                        FirstName = "Jon", LastName="Skeet"
                    },
                     new Author 
                    {
                        FirstName = "Jon", LastName="Skeet"
                    },                       
                }
            },
            new Book
            {
                Name="LINQ in Action",
                Authors = new List<Author>
                {
                    new Author 
                    {
                        FirstName = "Fabrice", LastName="Marguerie"
                    },
                     new Author 
                    {
                        FirstName = "Steve", LastName="Eichert"
                    },
                     new Author 
                    {
                        FirstName = "Jim", LastName="Wooley"
                    },
                }
            },
        };


        var temp = books.SelectMany(book => book.Authors).Distinct();
        foreach (var author in temp)
        {
            Console.WriteLine(author.FirstName + " " + author.LastName);
        }

        Console.Read();
    }

}
public class Book
{
    public string Name { get; set; }
    public List<Author> Authors { get; set; }
}
public class Author
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public override bool Equals(object obj)
    {
        return true;
        //if (obj.GetType() != typeof(Author)) return false;
        //else return ((Author)obj).FirstName == this.FirstName && ((Author)obj).FirstName == this.LastName;
    }

}

এটি "লিনিকিউ ইন অ্যাকশনে" উদাহরণের ভিত্তিতে তৈরি। তালিকা 4.16।

এটি জোন স্কিটকে দু'বার মুদ্রণ করে। কেন? এমনকি লেখক শ্রেণিতে আমি সমান পদ্ধতিতে ওভাররাইড করার চেষ্টা করেছি। এখনও ডিস্টিন্ট কাজ করে না বলে মনে হচ্ছে। আমি কী মিস করছি?

সম্পাদনা: আমি == এবং! = অপারেটর ওভারলোডও যুক্ত করেছি। এখনও কোন সাহায্য।

 public static bool operator ==(Author a, Author b)
    {
        return true;
    }
    public static bool operator !=(Author a, Author b)
    {
        return false;
    }

উত্তর:


159

কাস্টম অবজেক্টের কথা বলতে গেলে লিনকুই ডিস্ট্রিন্টটি তেমন স্মার্ট নয়।

এটি কেবল আপনার তালিকার দিকে তাকান এবং দেখুন যে এটির দুটি পৃথক বস্তু রয়েছে (এটি বিবেচ্য নয় যে তাদের সদস্য ক্ষেত্রগুলির জন্য একই মান রয়েছে)।

একটি কর্মসূচী হ'ল এখানে দেখানো হিসাবে আইকুয়েটেবল ইন্টারফেস প্রয়োগ করা ।

আপনি যদি নিজের লেখক শ্রেণিকে পছন্দ করেন তবে এটি কাজ করা উচিত।

public class Author : IEquatable<Author>
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public bool Equals(Author other)
    {
        if (FirstName == other.FirstName && LastName == other.LastName)
            return true;

        return false;
    }

    public override int GetHashCode()
    {
        int hashFirstName = FirstName == null ? 0 : FirstName.GetHashCode();
        int hashLastName = LastName == null ? 0 : LastName.GetHashCode();

        return hashFirstName ^ hashLastName;
    }
}

এটি ডটনেটফিডাল হিসাবে চেষ্টা করুন


22
আইক্যায়েটেবল ঠিক আছে তবে অসম্পূর্ণ; আপনার সর্বদা অবজেক্ট.এক্কুলস () এবং অবজেক্ট.গেটহ্যাশকোড () একসাথে প্রয়োগ করা উচিত ; আইক্যায়েটেবল <টি> .মানবস্তুগুলি অবজেক্ট.একওয়ালগুলিকে ওভাররাইড করে না, সুতরাং অ-দৃ .়ভাবে টাইপ করা তুলনা করার সময় এটি ব্যর্থ হবে, যা প্রায়শই ফ্রেমওয়ার্কে এবং সর্বদা জেনারিক সংগ্রহগুলিতে ঘটে।
অ্যান্ডিএম

তাই রেক্স এম এর পরামর্শ অনুসারে আইইকুয়ালি কম্পারার <টি> গ্রহণকারী ডিস্টিন্টের ওভাররাইড ব্যবহার করা কি ভাল? আমি বোঝাতে চাইছি যদি আমি ফাঁদে পড়তে চাই না তবে আমার কী করা উচিত।
তন্ময় 4

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

3
আমি প্রয়োগ করেছি IEquatable(এবং ওভাররড Equals/ GetHashCode) তবে আমার ব্রেকপয়েন্টগুলি কোনওই এই পদ্ধতিতে কোনও লিঙ্কে গুলি চালাচ্ছে না Distinct?
পিটারএক্স

2
@ পিটারএক্স আমি এটি লক্ষ্য করেছি। আমার ব্রেকপয়েন্ট ছিল GetHashCodeএবং Equals, সেগুলি ফোরচ লুপ চলাকালীন আঘাত পেয়েছিল। এর কারণটি একটি var temp = books.SelectMany(book => book.Authors).Distinct();ফেরত দেয় IEnumerable, যার অর্থ অনুরোধটি এখনই কার্যকর করা হয় না, কেবলমাত্র ডেটা ব্যবহার করার সময় এটি কার্যকর করা হয়। আপনি যদি এই মুহুর্তে এই গুলি চালানোর কোনও উদাহরণ চান, তবে এর .ToList()পরে যুক্ত করুন .Distinct()এবং আপনি ভবিষ্যতের পূর্বে Equalsএবং এর GetHashCodeআগে ব্রেকপয়েন্টগুলি দেখতে পাবেন ।
জ্যাবারওয়কিডেকম্পেলার

70

Distinct()রেফারেন্স ধরনের জন্য পদ্ধতি চেক রেফারেন্স সমতা। এর অর্থ এটি আক্ষরিকভাবে একই বস্তুর অনুলিপিটির সন্ধান করছে, ভিন্ন ভিন্ন বস্তুতে যা একই মান রয়েছে।

এখানে একটি ওভারলোড রয়েছে যা একটি আইকোয়ালিটি কম্পিউটারের নেয় , তাই প্রদত্ত বস্তুটি অন্যটির সমান কিনা তা নির্ধারণের জন্য আপনি বিভিন্ন যুক্তি নির্দিষ্ট করতে পারেন।

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

IEqualityComparerইন্টারফেসে দুই সদস্য হলেন Equalsএবং GetHashCode। দুটি Authorবস্তু সমান কিনা তা নির্ধারণের জন্য আপনার যুক্তিটি প্রথম এবং শেষ নামের স্ট্রিংগুলি একই হয় বলে মনে হয়।

public class AuthorEquals : IEqualityComparer<Author>
{
    public bool Equals(Author left, Author right)
    {
        if((object)left == null && (object)right == null)
        {
            return true;
        }
        if((object)left == null || (object)right == null)
        {
            return false;
        }
        return left.FirstName == right.FirstName && left.LastName == right.LastName;
    }

    public int GetHashCode(Author author)
    {
        return (author.FirstName + author.LastName).GetHashCode();
    }
}

1
ধন্যবাদ! আপনার গেটহ্যাশকোড () বাস্তবায়ন আমাকে দেখায় যে আমি কী অনুপস্থিত ছিল। আমি {পাস-ইন-অবজেক্ট returning। গেটহ্যাশকোড (), {তুলনা করার জন্য সম্পত্তি ব্যবহৃত হচ্ছে না returning .গেটহ্যাশকোড () ফিরে আসছিলাম। এটি তফাত্ করেছে এবং ব্যাখ্যা করে যে আমার এখনও ব্যর্থ হয়েছিল কেন - দুটি পৃথক উল্লেখে দুটি পৃথক হ্যাশ কোড থাকবে।
পেলাজেম

44

বাস্তবায়ন ছাড়া আরেকটি সমাধান IEquatable, Equalsএবং GetHashCodeLINQs ব্যবহার করা GroupByপদ্ধতি এবং IGrouping থেকে প্রথম বস্তুটি নির্বাচন করুন।

var temp = books.SelectMany(book => book.Authors)
                .GroupBy (y => y.FirstName + y.LastName )
                .Select (y => y.First ());

foreach (var author in temp){
  Console.WriteLine(author.FirstName + " " + author.LastName);
}

1
এটি কেবল আমাকে পারফরম্যান্স বিবেচনা করে সহায়তা করেছে, এটি কি একই গতিতে সঞ্চালন করে ?, উপরের পদ্ধতিগুলি বিবেচনা করে?
বিশ্বজিৎ

এটি বাস্তবায়নের পদ্ধতিগুলির সাথে জটিলতার চেয়ে আরও ভাল, এবং যদি EF ব্যবহার করা হয় তবে স্কেল সার্ভারে কাজটি অর্পণ করা হবে।
Zapnologica

এই পদ্ধতিটি কাজ করতে পারে এমন সময়ে, বিভিন্ন গোষ্ঠীভুক্ত জিনিসগুলির কারণে পারফরম্যান্সের সমস্যা হবে
বেলাশ

@ বেলাশ এটি কাজ করুন এটি দ্রুত করুন make নিশ্চিত যে এই গ্রুপিংয়ের ফলে আরও বেশি কাজ করা হতে পারে। তবে কখনও কখনও আপনার চেয়ে বেশি বাস্তবায়ন করা জটিল umbers
যিহোফ

2
আমি এই সমাধানটি পছন্দ করি তবে তারপরে গ্রুপবাইতে একটি "নতুন" অবজেক্টটি ব্যবহার করে: .GroupBy(y => new { y.FirstName, y.LastName })
ডেভ ডি জং

32

ব্যবহারকারীর সংজ্ঞায়িত ডেটা টাইপের তালিকা থেকে আলাদা মানগুলি পাওয়ার আরও একটি উপায় রয়েছে:

YourList.GroupBy(i => i.Id).Select(i => i.FirstOrDefault()).ToList();

অবশ্যই, এটি আলাদা আলাদা ডেটা দেবে


21

Distinct()গণনাযোগ্য বস্তুর উপর ডিফল্ট সমতা তুলনা সম্পাদন করে। যদি আপনি ওভাররাইড না করে থাকেন Equals()এবং GetHashCode(), তবে এটি ডিফল্ট বাস্তবায়ন ব্যবহার করে object, যা রেফারেন্সগুলির সাথে তুলনা করে।

সহজ সমাধান একটি যোগ হয় সঠিক বাস্তবায়ন Equals()এবং GetHashCode()সব শ্রেণীর যা বস্তুর গ্রাফ আপনি তুলনা করা হয় (যেমন বুক এবং লেখক) অংশগ্রহণের।

IEqualityComparerইন্টারফেস একটি সুবিধা যে আপনি বাস্তবায়ন করার মঞ্জুরি দেয় Equals()এবং GetHashCode()একটি পৃথক ক্লাসে আপনি ক্লাস তোমার তুলনা করতে হবে, অথবা আপনি তুলনা একটি ভিন্ন পদ্ধতি ব্যবহার করছেন কিনা তা এর অভ্যন্তরীণ এক্সেস আছে না তখন।


অংশগ্রহণকারী অবজেক্ট সম্পর্কে এই ব্রিল্যান্ট ধূমকেতকের জন্য আপনাকে অনেক ধন্যবাদ।
সুহিউরা

11

আপনি সমান () সমেতকে ছাড়িয়ে গেছেন তবে নিশ্চিত হয়ে নিন যে আপনি গেটহ্যাশকোড () কে ওভাররাইড করেছেন


গেটহ্যাশকোডকে জোর দেওয়ার জন্য +1) বেস হ্যাশকোড বাস্তবায়নটি যোগ করুন না<custom>^base.GetHashCode()
দানি

8

উপরের উত্তরগুলি ভুল! এমএসডিএন-তে বর্ণিত হিসাবে পৃথকীকরণটি ডিফল্ট নিরক্ষীয় ভূমিকম্পকে ফেরত দেয় যা বর্ণিত হিসাবে ডিফল্ট সম্পত্তি পরীক্ষা করে টাইপ টি সিস্টেম প্রয়োগ করে কিনা তা পরীক্ষা করে I অন্যথায়, এটি এমন একটি ইক্যুয়ালিটি কম্পিউটারকে ফেরৎ দেয় যা অবজেক্ট.এক্কেলস এবং অবজেক্টের ওভাররাইড ব্যবহার করে T টি সরবরাহ করে গেটহ্যাশকোড

যার অর্থ যতক্ষণ আপনি সমানকে ছাড়বেন ততক্ষণ আপনি ভাল আছেন।

আপনার কোডটি কাজ না করার কারণ হ'ল আপনি প্রথম নাম == লাস্ট নামটি পরীক্ষা করেছেন।

দেখতে https://msdn.microsoft.com/library/bb348436(v=vs.100).aspx এবং https://msdn.microsoft.com/en-us/library/ms224763(v=vs.100).aspx


0

আপনি তালিকায় এক্সটেনশন পদ্ধতি ব্যবহার করতে পারেন যা গণিত হ্যাশের ভিত্তিতে স্বতন্ত্রতা পরীক্ষা করে। IEnumerable সমর্থন করার জন্য আপনি এক্সটেনশন পদ্ধতিটিও পরিবর্তন করতে পারেন।

উদাহরণ:

public class Employee{
public string Name{get;set;}
public int Age{get;set;}
}

List<Employee> employees = new List<Employee>();
employees.Add(new Employee{Name="XYZ", Age=30});
employees.Add(new Employee{Name="XYZ", Age=30});

employees = employees.Unique(); //Gives list which contains unique objects. 

সম্প্রসারণ পদ্ধতি:

    public static class LinqExtension
        {
            public static List<T> Unique<T>(this List<T> input)
            {
                HashSet<string> uniqueHashes = new HashSet<string>();
                List<T> uniqueItems = new List<T>();

                input.ForEach(x =>
                {
                    string hashCode = ComputeHash(x);

                    if (uniqueHashes.Contains(hashCode))
                    {
                        return;
                    }

                    uniqueHashes.Add(hashCode);
                    uniqueItems.Add(x);
                });

                return uniqueItems;
            }

            private static string ComputeHash<T>(T entity)
            {
                System.Security.Cryptography.SHA1CryptoServiceProvider sh = new System.Security.Cryptography.SHA1CryptoServiceProvider();
                string input = JsonConvert.SerializeObject(entity);

                byte[] originalBytes = ASCIIEncoding.Default.GetBytes(input);
                byte[] encodedBytes = sh.ComputeHash(originalBytes);

                return BitConverter.ToString(encodedBytes).Replace("-", "");
            }

-1

আপনি দুটি উপায়ে এটি অর্জন করতে পারেন:

1. আপনি may IEquatable ইন্টারফেস বাস্তবায়ন দেখানো হয়েছে Enumerable.Distinct পদ্ধতি বা আপনি দেখতে পারেন এই পোষ্ট টা কি @ skalb এর উত্তর

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

উদাহরণস্বরূপ নীচের মত এবং আমার জন্য কাজ করা:

var distinctList= list.GroupBy(x => new {
                            Name= x.Name,
                            Phone= x.Phone,
                            Email= x.Email,
                            Country= x.Country
                        }, y=> y)
                       .Select(x => x.First())
                       .ToList()

মাইবজেক্ট ক্লাসটি নীচের মতো:

public class MyClass{
       public string Name{get;set;}
       public string Phone{get;set;}
       public string Email{get;set;}
       public string Country{get;set;}
}

৩. যদি আপনার অবজেক্টের অনন্য কী থাকে তবে আপনি এটিকে কেবলমাত্র গ্রুপ অনুসারে ব্যবহার করতে পারেন।

উদাহরণস্বরূপ, আমার বস্তুর অনন্য কী আইডি Id

var distinctList= list.GroupBy(x =>x.Id)
                      .Select(x => x.First())
                      .ToList()
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.