লিনাক ব্যবহার করে এবং ডুপ্লিকেট সম্পর্কে চিন্তিত না হয়ে অভিধানে অভিধানে রূপান্তর করুন


163

আমার কাছে ব্যক্তি বস্তুর একটি তালিকা রয়েছে। আমি এমন একটি অভিধানে রূপান্তর করতে চাই যেখানে কীটি হ'ল প্রথম এবং শেষ নাম (কনটেটেটেড) এবং মানটি ব্যক্তি অবজেক্ট।

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

private Dictionary<string, Person> _people = new Dictionary<string, Person>();

_people = personList.ToDictionary(
    e => e.FirstandLastName,
    StringComparer.OrdinalIgnoreCase);

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


1
সদৃশ (কী এর উপর ভিত্তি করে), আমি নিশ্চিত না যে আপনি এগুলি রাখতে চান বা তাদের হারাতে চান? এগুলি রাখার জন্য একটি Dictionary<string, List<Person>>(বা সমমানের) প্রয়োজন হবে ।
অ্যান্থনি পেগ্রাম

@ অ্যান্থনি পেগ্রাম - কেবল তাদের মধ্যে একটি রাখতে চান। আমি প্রশ্নটি আরও স্পষ্ট হতে আপডেট করেছি
লিওরা

ভাল আপনি ToD शब्दकोष করার আগে স্বতন্ত্র ব্যবহার করতে পারেন। তবে আপনাকে ব্যক্তি শ্রেণির জন্য সমান () এবং গেটহ্যাশকোড () পদ্ধতিগুলি ওভাররাইড করতে হবে যাতে সিএলআর কীভাবে ব্যক্তি
সামগ্রীর

@ সুজিৎ.ওয়েরিয়ার - আপনি পাস করার জন্য একটি সমতা তুলক তৈরি করতেও পেরেছিলেনDistinct
কাইল

উত্তর:


71

এখানে সুস্পষ্ট, অ লিঙ্ক সমাধান:

foreach(var person in personList)
{
  if(!myDictionary.Keys.Contains(person.FirstAndLastName))
    myDictionary.Add(person.FirstAndLastName, person);
}

207
তাই তাই 2007 :)
লেওরা


হ্যাঁ, প্রায় সময় আমরা কাজের সময় নেট নেট ফ্রেম ফ্রেম থেকে আপডেট করি ... @ তবে কেস উপেক্ষা করা ঠিক কঠিন নয়। বড় হাতের অক্ষরে সমস্ত কী যুক্ত করুন।
কারা

আমি কীভাবে এই
মামলাটিকে

11
অথবা একটি স্ট্রিংকম্পার দিয়ে অভিধান তৈরি করুন যা কেসটিকে উপেক্ষা করবে, যদি আপনার যা প্রয়োজন হয় তা যদি হয় তবে আপনার যুক্তকরণ / চেকিং কোডটি আপনি কেস উপেক্ষা করছেন কিনা তা বিবেচনা করে না।
বাইনারি ওয়ারিয়ার 15

423

লিনকিউ সমাধান:

// Use the first value in group
var _people = personList
    .GroupBy(p => p.FirstandLastName, StringComparer.OrdinalIgnoreCase)
    .ToDictionary(g => g.Key, g => g.First(), StringComparer.OrdinalIgnoreCase);

// Use the last value in group
var _people = personList
    .GroupBy(p => p.FirstandLastName, StringComparer.OrdinalIgnoreCase)
    .ToDictionary(g => g.Key, g => g.Last(), StringComparer.OrdinalIgnoreCase);

আপনি যদি একটি লিনকুইবিহীন সমাধানটি পছন্দ করেন তবে আপনি এর মতো কিছু করতে পারেন:

// Use the first value in list
var _people = new Dictionary<string, Person>(StringComparer.OrdinalIgnoreCase);
foreach (var p in personList)
{
    if (!_people.ContainsKey(p.FirstandLastName))
        _people[p.FirstandLastName] = p;
}

// Use the last value in list
var _people = new Dictionary<string, Person>(StringComparer.OrdinalIgnoreCase);
foreach (var p in personList)
{
    _people[p.FirstandLastName] = p;
}

2
+1 টি খুব মার্জিত (ঝ যত শীঘ্র সম্ভব ভোট দিতে হবে - আজকের জন্য আর কোনো ভোট :) আছে)
onof

6
@ লুকে মাইনর নোট: আপনার দুটি স্নিপেট সমতুল্য নয়: লিনকিউ ভেরিয়েন্টটি প্রথম উপাদানটিকে ধরে রাখে, নন-লিনকুই স্নিপেট শেষ উপাদানটি ধরে রাখে?
টুং

4
@ টুং: এটি সত্য এবং অবশ্যই লক্ষণীয়। (যদিও এই ক্ষেত্রে ওপি তাদের কোন উপাদানটি শেষ করবে
সেদিকে খেয়াল করে না

1
"প্রথম মান" ক্ষেত্রে: ননলিংক সমাধান দুটিবার অভিধানে অনুসন্ধান করে তবে লিনক অপ্রয়োজনীয় অবজেক্ট ইনস্ট্যান্টেশন এবং পুনরাবৃত্তি করে। দু'জনই আদর্শ নন।
সার্জ

@ সার্জ ধন্যবাদ, অভিধানের অনুসন্ধানটি সাধারণত একটি ও (1) অপারেশন হিসাবে বিবেচনা করা হয় এবং এটি একটি নগণ্য প্রভাব ফেলে।
এমহোলিস

42

ডিস্টিন্ট () ব্যবহার করে একটি লিঙ্ক-সমাধান এবং কোনও গ্রুপিং নয়:

var _people = personList
    .Select(item => new { Key = item.Key, FirstAndLastName = item.FirstAndLastName })
    .Distinct()
    .ToDictionary(item => item.Key, item => item.FirstFirstAndLastName, StringComparer.OrdinalIgnoreCase);

আমি জানি না যে এটি লুকএইচ এর সমাধানের চেয়ে ভাল কিনা তবে এটি কাজ করে।


আপনি কি নিশ্চিত যে কাজ করে? আপনার তৈরি নতুন রেফারেন্স টাইপের সাথে ডিস্টিন্ট কীভাবে তুলনা করতে চলেছে? আমি মনে করি এই কাজটি উদ্দেশ্য হিসাবে পেতে আপনার কিছু প্রকারের আইকুয়ালিটি কম্পিউটারকে আলাদা করার দরকার হবে pass
সাইমন গিলবি 15

5
আমার আগের মন্তব্যটি উপেক্ষা করুন। দেখুন stackoverflow.com/questions/543482/...
সাইমন Gillbee

আপনি যদি স্বতন্ত্রভাবে কীভাবে নির্ধারিত হয় তা ওভাররাইড করতে চান তাহলে চেক আউট করুন stackoverflow.com/questions/489258/…
জেমস ম্যাকমাহন

30

এটি ল্যাম্বডা এক্সপ্রেশন সহ কাজ করা উচিত:

personList.Distinct().ToDictionary(i => i.FirstandLastName, i => i);

2
এটি অবশ্যই হবে:personList.Distinct().ToDictionary(i => i.FirstandLastName, i => i);
Gh61

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

13

আপনি ToLookupলিনকিউ ফাংশনটিও ব্যবহার করতে পারেন যা আপনি পরে অভিধানের মাধ্যমে প্রায় বিনিময়যোগ্য হিসাবে ব্যবহার করতে পারেন।

_people = personList
    .ToLookup(e => e.FirstandLastName, StringComparer.OrdinalIgnoreCase);
_people.ToDictionary(kl => kl.Key, kl => kl.First()); // Potentially unnecessary

এটি লূকএইচ-এর উত্তরে গ্রুপবি দ্বারা মূলত করবে , তবে একটি অভিধান সরবরাহ করে এমন হ্যাশিং দেবে। সুতরাং, আপনার সম্ভবত এটি একটি অভিধানে রূপান্তর করার দরকার নেই, তবে Firstযখনই আপনি কীটির মানটি অ্যাক্সেস করতে হবে তখনই লিনকিউ ফাংশনটি ব্যবহার করুন ।


8

পার্থক্যটি যেহেতু এটি সদৃশগুলিকে অনুমোদন করে আপনি টোডেটরিওর () এর অনুরূপ একটি এক্সটেনশন পদ্ধতি তৈরি করতে পারেন। কিছুটা এইরকম:

    public static Dictionary<TKey, TElement> SafeToDictionary<TSource, TKey, TElement>(
        this IEnumerable<TSource> source, 
        Func<TSource, TKey> keySelector, 
        Func<TSource, TElement> elementSelector, 
        IEqualityComparer<TKey> comparer = null)
    {
        var dictionary = new Dictionary<TKey, TElement>(comparer);

        if (source == null)
        {
            return dictionary;
        }

        foreach (TSource element in source)
        {
            dictionary[keySelector(element)] = elementSelector(element);
        }

        return dictionary; 
    }

এই ক্ষেত্রে যদি নকল থাকে তবে সর্বশেষ মানটি জিততে পারে।


7

অনুলিপি অপসারণ পরিচালনা IEqualityComparer<Person>করতে Distinct(), পদ্ধতিতে ব্যবহার করা যেতে পারে এমন একটি বাস্তবায়ন করুন এবং তারপরে আপনার অভিধানটি পাওয়া সহজ হবে। প্রদত্ত:

class PersonComparer : IEqualityComparer<Person>
{
    public bool Equals(Person x, Person y)
    {
        return x.FirstAndLastName.Equals(y.FirstAndLastName, StringComparison.OrdinalIgnoreCase);
    }

    public int GetHashCode(Person obj)
    {
        return obj.FirstAndLastName.ToUpper().GetHashCode();
    }
}

class Person
{
    public string FirstAndLastName { get; set; }
}

আপনার অভিধান পান:

List<Person> people = new List<Person>()
{
    new Person() { FirstAndLastName = "Bob Sanders" },
    new Person() { FirstAndLastName = "Bob Sanders" },
    new Person() { FirstAndLastName = "Jane Thomas" }
};

Dictionary<string, Person> dictionary =
    people.Distinct(new PersonComparer()).ToDictionary(p => p.FirstAndLastName, p => p);

2
        DataTable DT = new DataTable();
        DT.Columns.Add("first", typeof(string));
        DT.Columns.Add("second", typeof(string));

        DT.Rows.Add("ss", "test1");
        DT.Rows.Add("sss", "test2");
        DT.Rows.Add("sys", "test3");
        DT.Rows.Add("ss", "test4");
        DT.Rows.Add("ss", "test5");
        DT.Rows.Add("sts", "test6");

        var dr = DT.AsEnumerable().GroupBy(S => S.Field<string>("first")).Select(S => S.First()).
            Select(S => new KeyValuePair<string, string>(S.Field<string>("first"), S.Field<string>("second"))).
           ToDictionary(S => S.Key, T => T.Value);

        foreach (var item in dr)
        {
            Console.WriteLine(item.Key + "-" + item.Value);
        }

আমি আপনাকে ন্যূনতম, সম্পূর্ণ এবং যাচাইযোগ্য উদাহরণ পড়ে আপনার উদাহরণটি উন্নত করার পরামর্শ দিচ্ছি ।
ইলগালা

2

যদি আমরা প্রত্যাবর্তনশীল অভিধানে সমস্ত ব্যক্তি (কেবলমাত্র একজন ব্যক্তির পরিবর্তে) চাই, আমরা করতে পারি:

var _people = personList
.GroupBy(p => p.FirstandLastName)
.ToDictionary(g => g.Key, g => g.Select(x=>x));

1
দুঃখিত, আমার পর্যালোচনা-সম্পাদনা উপেক্ষা করুন (আমার পর্যালোচনা-সম্পাদনাটি কোথায় মুছতে হবে তা আমি খুঁজে পাই না)। আমি কেবল g.Select (x => x) এর পরিবর্তে g.First () ব্যবহার সম্পর্কে একটি পরামর্শ যুক্ত করতে চেয়েছিলাম।
অ্যালেক্স 75

1

অন্যান্য উত্তর অধিকাংশ সমস্যাটির যে, তারা ব্যবহার করেন Distinct, GroupByবা ToLookupযা ফণা অধীন একটি অতিরিক্ত অভিধান সৃষ্টি। সমানভাবে টুপার অতিরিক্ত স্ট্রিং তৈরি করে। এটি আমিই করেছি, যা মাইক্রোসফ্টের কোডের একটি হুবহু অনুলিপি ছাড়া একটি পরিবর্তন ব্যতীত:

    public static Dictionary<TKey, TSource> ToDictionaryIgnoreDup<TSource, TKey>
        (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer = null) =>
        source.ToDictionaryIgnoreDup(keySelector, i => i, comparer);

    public static Dictionary<TKey, TElement> ToDictionaryIgnoreDup<TSource, TKey, TElement>
        (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer = null)
    {
        if (keySelector == null)
            throw new ArgumentNullException(nameof(keySelector));
        if (elementSelector == null)
            throw new ArgumentNullException(nameof(elementSelector));
        var d = new Dictionary<TKey, TElement>(comparer ?? EqualityComparer<TKey>.Default);
        foreach (var element in source)
            d[keySelector(element)] = elementSelector(element);
        return d;
    }

যেহেতু সূচকগুলিতে একটি সেট এটি চাবি যুক্ত করার কারণ হ'ল এটি নিক্ষেপ করবে না এবং কেবলমাত্র একটি কী অনুসন্ধান করবে। IEqualityComparerউদাহরণস্বরূপ আপনি এটি একটিও দিতে পারেনStringComparer.OrdinalIgnoreCase


0

কারার সমাধান থেকে শুরু করে আপনি এটিকে এইভাবে লিখতে পারেন:

foreach(var person in personList.Where(el => !myDictionary.ContainsKey(el.FirstAndLastName)))
{
    myDictionary.Add(person.FirstAndLastName, person);
}

3
কেউ কখনও এটি ব্যবহার করার চেষ্টা করবেন না এমন নয়, তবে এটি ব্যবহারের চেষ্টা করবেন না। সংগ্রহগুলি পুনরাবৃত্তি করার সাথে সাথে তাদের সংশোধন করা একটি খারাপ ধারণা।
কিডমোজে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.