কীভাবে লিনাকের ফলাফলগুলি হ্যাশসেট বা হ্যাশডসেটে রূপান্তর করা যায়


195

আমার ক্লাসে একটি সম্পত্তি রয়েছে যা একটি ইসেট। আমি সেই সম্পত্তিটিতে লিনিক ক্যোয়ারির ফলাফল পাওয়ার চেষ্টা করছি, তবে কীভাবে এটি করা যায় তা অনুমান করতে পারি না।

মূলত, এর শেষ অংশটি সন্ধান করুন:

ISet<T> foo = new HashedSet<T>();
foo = (from x in bar.Items select x).SOMETHING;

এটি করতে পারে:

HashSet<T> foo = new HashSet<T>();
foo = (from x in bar.Items select x).SOMETHING;

আমার মনে হয় আপনার HashedSetপার্টটি ছেড়ে দেওয়া উচিত । এটি কেবল বিভ্রান্তিকর C#এবং এর LINQকোনও কল নেই HashedSet

উত্তরগুলি প্রশ্নাবলীতে নয়, উত্তর-বাক্সগুলিতে যায়। আপনি যদি নিজের প্রশ্নের উত্তর দিতে চান, যা এসও বিধি দ্বারা পুরোপুরি ঠিক আছে, দয়া করে এর জন্য একটি উত্তর লিখুন।
অ্যাড্রায়ান

উত্তর:


307

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

public static class Extensions
{
    public static HashSet<T> ToHashSet<T>(
        this IEnumerable<T> source,
        IEqualityComparer<T> comparer = null)
    {
        return new HashSet<T>(source, comparer);
    }
}

নোট করুন যে আপনি এখানে একটি এক্সটেনশন পদ্ধতি (বা কমপক্ষে কোনও ফর্মের জেনেরিক পদ্ধতি) চান, কারণ আপনি Tস্পষ্টভাবে প্রকারটি প্রকাশ করতে পারবেন না :

var query = from i in Enumerable.Range(0, 10)
            select new { i, j = i + 1 };
var resultSet = query.ToHashSet();

আপনি এটি HashSet<T>নির্মাণকারীর কাছে একটি সুস্পষ্ট কল দিয়ে করতে পারবেন না । আমাদের পক্ষে এটি করার জন্য জেনেরিক পদ্ধতিগুলির জন্য আমরা টাইপ অনুক্রমের উপর নির্ভর করছি।

এখন আপনি পারে এটির নাম করা চয়ন ToSetএবং বিনিময়েISet<T> - তবে আমি ToHashSetএবং কংক্রিটের ধরণের সাথে আঁকছি। এই মান LINQ অপারেটার (সঙ্গে সামঞ্জস্যপূর্ণ ToDictionary, ToList) এবং ভবিষ্যতে সম্প্রসারণ (যেমন জন্য করতে পারবেন ToSortedSet)। আপনি ব্যবহারের তুলনা নির্দিষ্ট করে একটি ওভারলোড সরবরাহ করতে চাইতে পারেন।


2
বেনামি ধরণের উপর ভাল পয়েন্ট। তবে, বেনামে কি দরকারী ওভাররাইডগুলি ব্যবহার করে GetHashCodeএবং Equals? যদি তা না হয় তবে তারা হ্যাশসেটে তেমন ভাল হতে পারে না ...
জোয়েল মুলার

4
@ জোয়েল: হ্যাঁ, তারা করে। অন্যথায় সমস্ত ধরণের জিনিস ব্যর্থ হবে। স্বীকৃত যে তারা কেবলমাত্র উপাদানগুলির জন্য ডিফল্ট সমতা তুলনামূলক ব্যবহার করে তবে সাধারণত এটি যথেষ্ট ভাল।
জন স্কেটি

2
@ জোনস্কিট - টোডোরিয়ালি এবং টোললিস্টের পাশাপাশি স্ট্যান্ডার্ড লিনকিউ অপারেটরগুলিতে এটি সরবরাহ না করার কোনও কারণ আছে কি জানেন? আমি শুনেছি যে প্রায়শই এমন কারণগুলি বাদ দেওয়ার কারণগুলির ভাল কারণগুলি রয়েছে, অনুপস্থিত আইকনুয়েবল <T> এর মতো Forএকটি পদ্ধতি
স্টিফেন হল্ট

1
@ স্টেফেনহোল্ট: আমি এর সাথে প্রতিরোধের সাথে একমত হই ForEach, তবে ToHashSetআরও অনেক বেশি অর্থবোধ করি - ToHashSetসাধারণ "ইউটিলিটি বারের সাথে দেখা করে না" (যেটার সাথে আমি একমত নই, তবে অন্য কিছু না করার কারণ আমি জানি না) ...)
জন স্কিটি

1
@ অ্যারন: নিশ্চিত নন ... সম্ভবত কারণ এটি লিনিক-টু-অবজেক্ট সরবরাহকারীদের পক্ষে সহজ না? (আমি এটি কল্পনাও করতে পারি না এটি অক্ষম, স্বীকারোক্তিযুক্ত)
জন স্কিটি

75

কেবলমাত্র হ্যাশসেটের কনস্ট্রাক্টরের জন্য আপনার অনুমানযোগ্য পাস করুন।

HashSet<T> foo = new HashSet<T>(from x in bar.Items select x);

2
আপনি কীভাবে কোনও প্রজেকশন সহ্য করতে যাচ্ছেন যার ফলস্বরূপ একটি বেনামি ধরণের?
জন স্কিটি

7
@ জন, আমি ধরে নিলাম যে এটি ইয়াজিএনআই অন্যথায় নিশ্চিত না হওয়া পর্যন্ত।
অ্যান্টনি পেগ্রাম

1
স্পষ্টত আমি নেই। ভাগ্যক্রমে, এই বিশেষ উদাহরণে, আমার দরকার নেই।
জোয়েল মুয়েলার

@ জনের প্রকারটি ওপি দ্বারা নির্দিষ্ট করা হয়েছে (প্রথম লাইনটি অন্যথায় সংকলন করবে না) সুতরাং এই ক্ষেত্রে আমি একমত হতে হবে এটি আপাতত YAGNI
রুন এফএস

2
@ রুন এফএস: এই ক্ষেত্রে, আমি সন্দেহ করি যে নমুনা কোডটি বাস্তববাদী নয়। একটি টাইপ প্যারামিটার টি পাওয়া খুব দুর্লভ তবে জানেন যে প্রতিটি আইটেম হতে bar.Itemsচলেছে T। এই সাধারণ উদ্দেশ্যটি তৈরি করা কতটা সহজ, এবং লিনিকিউ-তে প্রায়শই বেনামে কীভাবে আসে তা দেওয়া যায় বলে আমি মনে করি যে এটি অতিরিক্ত পদক্ষেপ নেওয়া উপযুক্ত।
জন স্কিটি


19

@ জোয়েল যেমন বলেছে, আপনি কেবলমাত্র আপনার সংখ্যাটি পাস করতে পারেন can আপনি যদি কোনও এক্সটেনশন পদ্ধতি করতে চান তবে আপনি এটি করতে পারেন:

public static HashSet<T> ToHashSet<T>(this IEnumerable<T> items)
{
    return new HashSet<T>(items);
}

3

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

public static ISet<T> EnsureSet<T>(this IEnumerable<T> source)
{
    ISet<T> result = source as ISet<T>;
    if (result != null)
        return result;
    return new HashSet<T>(source);
}

কারণটি হ'ল, ব্যবহারকারীরা ISetইতিমধ্যে আপনার পদ্ধতিটি কল করতে পারে তাই আপনার অনুলিপি তৈরি করার দরকার নেই।


3

.NET ফ্রেমওয়ার্ক এবং একটিকে রূপান্তর IEnumerableকরার জন্য। নেট কোরটিতে একটি এক্সটেনশন পদ্ধতি রয়েছে HashSet: https://docs.microsoft.com/en-us/dotnet/api/?term=ToHashSet

public static System.Collections.Generic.HashSet<TSource> ToHashSet<TSource> (this System.Collections.Generic.IEnumerable<TSource> source);

এটি প্রদর্শিত হয় যে আমি এটি এখনও .NET স্ট্যান্ডার্ড লাইব্রেরিতে ব্যবহার করতে পারি না (লেখার সময়)। সুতরাং আমি এই এক্সটেনশন পদ্ধতিটি ব্যবহার করি:

    [Obsolete("In the .NET framework and in NET core this method is available, " +
              "however can't use it in .NET standard yet. When it's added, please remove this method")]
public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source, IEqualityComparer<T> comparer = null) => new HashSet<T>(source, comparer);

2

এটা বেশ সহজ :)

var foo = new HashSet<T>(from x in bar.Items select x);

এবং হ্যাঁ টি হ'ল ওপেন দ্বারা নির্দিষ্ট প্রকার :)


এটি কোনও ধরণের আর্গুমেন্ট নির্দিষ্ট করে না।
জন স্কিটি

যে লোলটি এখনকার সবচেয়ে কঠোরতম ভোট হতে পারে :) :) আমার কাছে এখন ঠিক একই তথ্য। টাইপ ইনফারেন্স সিস্টেমটি ইতিমধ্যে যাইহোক এই ধরণের অনুমান করছে না তা আমাকে মারছে :)
রুন এফএস

এখনই পূর্বাবস্থায় ফিরিয়ে আনুন ... তবে এটি প্রকৃতপক্ষে স্পষ্টভাবে উল্লেখযোগ্য কারণ আপনি টাইপ অনুমানটি পান না। আমার উত্তর দেখুন।
জন স্কেটি

2
আমি এরিকের ব্লগে এটি দেখতে পেয়ে মনে করতে পারি না কারণ কেন নির্মাণকারীদের উপর অনুমান করা সেই অনুমানের অংশ নয় কেন আপনি জানেন?
রুন এফ এস

1

জনের উত্তর নিখুঁত। একমাত্র সতর্কতাটি হ'ল, এনএইচবারনেটের হ্যাশডসেটটি ব্যবহার করে, ফলাফলগুলি সংগ্রহে রূপান্তর করতে হবে। এটি করার একটি সর্বোত্তম উপায় আছে?

ISet<string> bla = new HashedSet<string>((from b in strings select b).ToArray()); 

অথবা

ISet<string> bla = new HashedSet<string>((from b in strings select b).ToList()); 

নাকি আমি অন্য কিছু মিস করছি?


সম্পাদনা করুন: আমি এটাই শেষ করেছি:

public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source)
{
    return new HashSet<T>(source);
}

public static HashedSet<T> ToHashedSet<T>(this IEnumerable<T> source)
{
    return new HashedSet<T>(source.ToHashSet());
}

ToListসাধারণত তুলনায় আরও দক্ষ ToArray। এটি কি বাস্তবায়নের প্রয়োজন ICollection<T>?
জন স্কেটি

সঠিক। আমি আপনার পদ্ধতিতে গিয়ে শেষ করেছিলাম, তারপরে ToHashedSet করতে এটি ব্যবহার করে (মূল প্রশ্নে সম্পাদনা দেখুন)। আপনার সাহায্যের জন্য ধন্যবাদ.
জেমি

0

আইশনামেবলকে হ্যাশসেটে রূপান্তর করার পরিবর্তে, অন্য কোনও বস্তুর সম্পত্তি হ্যাশসেটে রূপান্তর করা প্রায়শই সুবিধাজনক। আপনি এটি লিখতে পারেন:

var set = myObject.Select(o => o.Name).ToHashSet();

তবে, আমার পছন্দটি নির্বাচকদের ব্যবহার করা হবে:

var set = myObject.ToHashSet(o => o.Name);

তারা একই কাজ করে, এবং দ্বিতীয়টি স্পষ্টতই সংক্ষিপ্ত, তবে আমি মূর্তিটি আমার মস্তিস্ককে আরও ভাল ফিট করে (

বোনাস হিসাবে কাস্টম তুলনাকারীদের সমর্থন সহ, এখানে ব্যবহারের জন্য এক্সটেনশন পদ্ধতি।

public static HashSet<TKey> ToHashSet<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> selector,
    IEqualityComparer<TKey> comparer = null)
{
    return new HashSet<TKey>(source.Select(selector), comparer);
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.