সি # তে অভিধানগুলি মার্জ করা হচ্ছে


493

2 বা ততোধিক অভিধানকে একত্রিত করার সর্বোত্তম উপায় কী (Dictionary<T1,T2> # ) সি # ? (লিনকিউ এর মতো 3.0.০ টি বৈশিষ্ট্য ভাল আছে)।

আমি এর লাইন বরাবর একটি পদ্ধতি স্বাক্ষরের কথা ভাবছি:

public static Dictionary<TKey,TValue>
                 Merge<TKey,TValue>(Dictionary<TKey,TValue>[] dictionaries);

অথবা

public static Dictionary<TKey,TValue>
                 Merge<TKey,TValue>(IEnumerable<Dictionary<TKey,TValue>> dictionaries);

সম্পাদনা: জারেডপার এবং জোন স্কিটের কাছ থেকে একটি দুর্দান্ত সমাধান পেয়েছি, তবে আমি এমন কোনও বিষয় নিয়ে ভাবছিলাম যা সদৃশ কীগুলি পরিচালনা করে। সংঘর্ষের ক্ষেত্রে এটি যতক্ষণ না সঙ্গতিপূর্ণ ততক্ষণ ডেকের কাছে কোন মান সংরক্ষণ করা যায় তা বিবেচ্য নয়।


174
সম্পর্কিত নয়, তবে dicA.Concat(dicB).ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
যেহেতু

6
@ বেঞ্জল আপনি উত্তর বিভাগে এটি যোগ করতে পারতেন
এম কুমারান

4
ক্লোজুরের সি # তে মিশে:dict1.Concat(dict2).GroupBy(p => p.Key).ToDictionary(g => g.Key, g => g.Last().Value)
ব্রুস

@ বেঞ্জল: প্রথম অভিধান থেকে এন্ট্রি পছন্দ করে সদৃশগুলি মুছে ফেলুন dictA.Concat(dictB.Where(kvp => !dictA.ContainsKey(kvp.Key))).ToDictionary(kvp=> kvp.Key, kvp => kvp.Value)
সানক্যাট 2000

উত্তর:


320

আপনি যদি সদৃশগুলিতে দৌড়ান তবে আপনি কী হতে চান তার উপর এটি আংশিকভাবে নির্ভর করে। উদাহরণস্বরূপ, আপনি এটি করতে পারেন:

var result = dictionaries.SelectMany(dict => dict)
                         .ToDictionary(pair => pair.Key, pair => pair.Value);

যদি আপনি কোনও সদৃশ কী পান তবে এটি ব্যতিক্রম করবে।

সম্পাদনা: আপনি যদি টুকলুকআপ ব্যবহার করেন তবে আপনি এমন একটি চেহারা পাবেন যাতে প্রতি একাধিক মান থাকতে পারে। আপনি পারে তারপর একটি অভিধান যে রূপান্তর:

var result = dictionaries.SelectMany(dict => dict)
                         .ToLookup(pair => pair.Key, pair => pair.Value)
                         .ToDictionary(group => group.Key, group => group.First());

এটি কিছুটা কুৎসিত - এবং অদক্ষ - তবে কোডের দিক দিয়ে এটি করার দ্রুততম উপায়। (আমি এটি পরীক্ষা করে দেখিনি, স্বীকার করে নিয়েছি।)

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


3
প্রথম অভিধান থেকে কেবল মূল্য নেওয়ার পরিবর্তে মানগুলি একত্রিত করার জন্য আপনি গ্রুপ => গোষ্ঠী থেকে প্রথম =) প্রতিস্থাপন করতে পারেন Jon জোন স্কিটের সম্পাদিত উত্তরে সিলিকটম্যানি (মান => মান)।
andreialecu

3
এখন আমি ভাবছি যে টু লুকআপের চেয়ে গ্রুপবাই আরও উপযুক্ত হবে? আমি মনে করি আইলুকআপ কেবল একটি সূচক, আকারের সম্পত্তি যুক্ত করে এবং আইগ্রুপিংয়ের শীর্ষে পদ্ধতি রয়েছে - তাই এটি খুব সামান্য দ্রুত হয়ে উঠতে পারে?
টুং

2
@ টুং: সত্যই সত্য হওয়া উচিত fine ব্যবহার করা GroupByসত্যিই কিছুটা দক্ষ হতে পারে - তবে আমি সন্দেহ করি যে এটি উভয় উপায়েই গুরুত্বপূর্ণ হবে।
জন স্কিটি

1
@ জো: ToDictionaryপদ্ধতি কলটিতে তুলনামূলক সরবরাহ করে এটি যথেষ্ট সহজ । যদিও আমি উত্তরটিকে আরও সাধারণ ক্ষেত্রে সহজ করে তুলতে পছন্দ করব এবং আমি আশা করি যে যার জন্য কাস্টম তুলনাকারীর প্রয়োজন তা প্রাসঙ্গিক ওভারলোড সন্ধানে সক্ষম।
জন স্কিটি

1
@ সার্জ: আমি আপনাকে সুনির্দিষ্ট প্রয়োজনীয়তা সহ একটি নতুন প্রশ্ন জিজ্ঞাসা করার পরামর্শ দিচ্ছি।
জন স্কিটি

264

আমি এটি এইভাবে করব:

dictionaryFrom.ToList().ForEach(x => dictionaryTo.Add(x.Key, x.Value));

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

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


169
যদি সদৃশ পদার্থের ব্যবহার হয় তবে ব্যবহার করুন dictionaryFrom.ToList().ForEach(x => dictionaryTo[x.Key] = x.Value)। এইভাবে dictionaryFromসম্ভবত বিদ্যমান কীটির জন্য মানকে ওভাররাইড থেকে মানগুলি ।
rum

7
এটি কোনও লুপের চেয়ে দ্রুততর হওয়ার সম্ভাবনা নেই - আপনি ভুলে গেছেন যে টোললিস্ট () আসলে অভিধানটি অনুলিপি করে শেষ করে। দ্রুততর কোড যদিও! ;-)
সেরেন বোইসেন

6
এটি দ্রুততর .. যেহেতু ToList () আসলে অভিধান অনুলিপি করে না, এটি কেবলমাত্র তাদের ভিতরে থাকা উপাদানগুলির রেফারেন্সগুলি অনুলিপি করে। মূলত তালিকার অবজেক্টটিতেই মেমরিতে নতুন ঠিকানা থাকবে, অবজেক্ট একই রকম !!
গুরুসি

4
ব্লগ পোস্টটি নিখোঁজ হয়েছে
সিএডি

1
হুম, বেশী ভালো জন স্কিট এর উত্তর, আমি অনুমান করে।
এস ই

102

যদি একাধিক কী ("রাইটার" কীগুলি "লেফটার" কীগুলি প্রতিস্থাপন করে) থাকে তবে এটি বিস্ফোরিত হয় না, বেশ কয়েকটি অভিধানকে মার্জ করতে পারে (যদি ইচ্ছা হয়) এবং প্রকারটি সংরক্ষণ করে (এটিতে সার্থক ডিফল্ট পাবলিক কনস্ট্রাক্টরের প্রয়োজন হয় এমন সীমাবদ্ধতার সাথে):

public static class DictionaryExtensions
{
    // Works in C#3/VS2008:
    // Returns a new dictionary of this ... others merged leftward.
    // Keeps the type of 'this', which must be default-instantiable.
    // Example: 
    //   result = map.MergeLeft(other1, other2, ...)
    public static T MergeLeft<T,K,V>(this T me, params IDictionary<K,V>[] others)
        where T : IDictionary<K,V>, new()
    {
        T newMap = new T();
        foreach (IDictionary<K,V> src in
            (new List<IDictionary<K,V>> { me }).Concat(others)) {
            // ^-- echk. Not quite there type-system.
            foreach (KeyValuePair<K,V> p in src) {
                newMap[p.Key] = p.Value;
            }
        }
        return newMap;
    }

}

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

2
আমি এই সমাধানটি পছন্দ করেছি, তবে একটি সতর্কতা রয়েছে: অভিধানটি this T meব্যবহার করে new Dictionary<string, T>(StringComparer.InvariantCultureIgnoreCase)বা অন্য কিছু অনুরূপ হিসাবে ঘোষিত হলে ফলস্বরূপ অভিধানটি একই আচরণ বজায় রাখতে পারবে না।
জোও পোর্তেলা

3
আপনি যদি meএকটি তৈরি করেন তবে আপনি এটি করতে Dictionary<K,V>পারেন var newMap = new Dictionary<TKey, TValue>(me, me.Comparer);এবং আপনি অতিরিক্ত Tধরণের পরামিতি এড়াতে পারেন ।
এনিভেস

1
এই প্রাণীটি কীভাবে ব্যবহার করা যায় তার কোনও উদাহরণ আছে?
টিম

1
@ টিম: আমি নীচে জানোয়ারের জন্য একটি উদাহরণ যুক্ত করেছি, আমি আনভিস দ্বারা সমাধানটি যুক্ত করেছি এবং ফলাফলটি একটি আরও গৃহপালিত জন্তু :)
কেনি

50

তুচ্ছ সমাধানটি হ'ল:

using System.Collections.Generic;
...
public static Dictionary<TKey, TValue>
    Merge<TKey,TValue>(IEnumerable<Dictionary<TKey, TValue>> dictionaries)
{
    var result = new Dictionary<TKey, TValue>();
    foreach (var dict in dictionaries)
        foreach (var x in dict)
            result[x.Key] = x.Value;
    return result;
}

22

নিম্নলিখিত চেষ্টা করুন

static Dictionary<TKey, TValue>
    Merge<TKey, TValue>(this IEnumerable<Dictionary<TKey, TValue>> enumerable)
{
    return enumerable.SelectMany(x => x).ToDictionary(x => x.Key, y => y.Value);
}

19
Dictionary<String, String> allTables = new Dictionary<String, String>();
allTables = tables1.Union(tables2).ToDictionary(pair => pair.Key, pair => pair.Value);

1
শুধু ভাবছি - শুধু ইউনিয়ন কি কাজ করবে না ? foreach(var kvp in Message.GetAttachments().Union(mMessage.GetImages()))প্রোডাকশন কোডে এটি ব্যবহার করে যদি কোনও ডাউনসাইড থাকে তবে দয়া করে আমাকে জানান! :)
মার্স রবার্টসন

1
@ মিচাল: ইউনিয়ন এমন একটি IEnumerable<KeyValuePair<TKey, TValue>>জায়গায় ফিরে আসবে যেখানে মূল এবং মানের সমতা দ্বারা সমতা সংজ্ঞায়িত করা হয় (বিকল্পের জন্য অনুমতি দেওয়ার জন্য একটি ওভারলোড রয়েছে)। এটি পূর্ববর্তী লুপের জন্য সূক্ষ্ম, যেখানে এটি প্রয়োজনীয় সমস্ত কিছু, তবে এমন ঘটনাও রয়েছে যেখানে আপনি আসলে অভিধানটি চান।
টিমোথি

15

আমি পার্টিতে খুব দেরি করেছি এবং সম্ভবত কিছু অনুপস্থিত, তবে যদি কোনও ডুপ্লিকেট কী না থাকে বা যেমন ওপি বলেছে, "সংঘর্ষের ক্ষেত্রে, ডিকের কাছে যতটা মূল্য সংরক্ষণ করা হবে ততক্ষণ তা বিবেচ্য নয় it's সামঞ্জস্যপূর্ণ, "এইটি দিয়ে কী ভুল হয়েছে (ডি 2 কে ডি 1 তে মিশে গেছে)?

foreach (KeyValuePair<string,int> item in D2)
            {
                 D1[item.Key] = item.Value;
            }

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


4
সবচেয়ে পরিষ্কার এবং সর্বাধিক পঠনযোগ্য সমাধানগুলির মধ্যে একটি ইমো এবং টোললিস্ট () ব্যবহার করুন যা অন্য অনেকে ব্যবহার করেন।
404

15

নিম্নলিখিত আমার জন্য কাজ করে। যদি সদৃশ থাকে তবে এটি ডোকা এর মান ব্যবহার করবে।

public static IDictionary<TKey, TValue> Merge<TKey, TValue>(this IDictionary<TKey, TValue> dictA, IDictionary<TKey, TValue> dictB)
    where TValue : class
{
    return dictA.Keys.Union(dictB.Keys).ToDictionary(k => k, k => dictA.ContainsKey(k) ? dictA[k] : dictB[k]);
}

@ এসবেনস্কভ পিডারসান আমি মনে করি না যে আমি এর মুখোমুখি হয়েছি যখন আমি এই উত্তরটি দিয়েছি (নতুন সি # দেব)
ইথান রিসর

আমাকে গাইডের মান হিসাবে ব্যবহার করতে 'যেখানে টিভিয়াল: শ্রেণি' সরিয়ে ফেলতে হয়েছিল
om471987

@ om471987 হ্যাঁ, গাইড একটি কাঠামো একটি শ্রেণি নয়, যাতে এটি বোঝা যায়। আমি মনে করি যে আমি যখন এই ধারাটি যুক্ত না করলাম তখন মূলত আমার কিছু সমস্যা হয়েছিল। আর কেন মনে নেই।
ইথান রিসর

10

এখানে আমি ব্যবহার করি এমন একটি সহায়ক ফাংশন:

using System.Collections.Generic;
namespace HelperMethods
{
    public static class MergeDictionaries
    {
        public static void Merge<TKey, TValue>(this IDictionary<TKey, TValue> first, IDictionary<TKey, TValue> second)
        {
            if (second == null || first == null) return;
            foreach (var item in second) 
                if (!first.ContainsKey(item.Key)) 
                    first.Add(item.Key, item.Value);
        }
    }
}

এখানে অনেকগুলি দুর্দান্ত সমাধান তালিকাভুক্ত রয়েছে তবে আমি বরং এর সরলতাকে সবচেয়ে বেশি পছন্দ করি। শুধু আমার ব্যক্তিগত পছন্দ।
জেসন

3
if(first == null)তাহলে এই যুক্তিটি অকেজো কারণ firstএটি না refএবং ফিরে আসে না। এবং এটি হতে পারে না refকারণ এটি একটি ইন্টারফেস উদাহরণ হিসাবে ঘোষিত হয়েছে; আপনাকে হয় ত্রুটি-চেক অপসারণ করতে হবে বা এটিকে শ্রেণীর উদাহরণ হিসাবে ঘোষণা করতে হবে বা একটি নতুন অভিধান (কোনও এক্সটেনশন পদ্ধতি ছাড়াই) ফিরিয়ে দিতে হবে।
গ্রেট

@ জেসিডিসিপল - আপনার পরামর্শ অনুসারে বিষয়টি সরিয়ে নিয়েছে
অ্যান্ড্রু হ্যারি

8

বিকল্প 1: এটি আপনি কী হতে চান তার উপর নির্ভর করে যদি আপনি নিশ্চিত হন যে আপনার কাছে উভয় অভিধানে নকল কী নেই। আপনি করতে চেয়ে পারে:

var result = dictionary1.Union(dictionary2).ToDictionary(k => k.Key, v => v.Value)

দ্রষ্টব্য: অভিধানে যদি কোনও সদৃশ কী পান তবে এটি ত্রুটি ফেলবে।

বিকল্প 2: আপনার যদি সদৃশ কী থাকতে পারে তবে আপনাকে যেখানে ক্লুপটি ব্যবহার করে সদৃশ কীটি পরিচালনা করতে হবে।

var result = dictionary1.Union(dictionary2.Where(k => !dictionary1.ContainsKey(k.Key))).ToDictionary(k => k.Key, v => v.Value)

দ্রষ্টব্য: এটি সদৃশ কী পাবেন না। অভিধানের কী-এর চেয়ে কোনও সদৃশ কী যদি পাওয়া যায়।

অপশন 3: আপনি টলকআপ ব্যবহার করতে চাইলে। তারপরে আপনি এমন এক নজরে পাবেন যাতে প্রতি একাধিক মান থাকতে পারে। আপনি সেই চেহারাটিকে অভিধানে রূপান্তর করতে পারেন:

var result = dictionaries.SelectMany(dict => dict)
                         .ToLookup(pair => pair.Key, pair => pair.Value)
                         .ToDictionary(group => group.Key, group => group.First());

6

কীভাবে একটি paramsওভারলোড যুক্ত করবেন?

এছাড়াও, আপনার IDictionaryসর্বোচ্চ নমনীয়তার জন্য এগুলি টাইপ করা উচিত ।

public static IDictionary<TKey, TValue> Merge<TKey, TValue>(IEnumerable<IDictionary<TKey, TValue>> dictionaries)
{
    // ...
}

public static IDictionary<TKey, TValue> Merge<TKey, TValue>(params IDictionary<TKey, TValue>[] dictionaries)
{
    return Merge((IEnumerable<TKey, TValue>) dictionaries);
}

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

5

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

    public static void MergeOverwrite<T1, T2>(this IDictionary<T1, T2> dictionary, IDictionary<T1, T2> newElements)
    {
        if (newElements == null) return;

        foreach (var e in newElements)
        {
            dictionary.Remove(e.Key); //or if you don't want to overwrite do (if !.Contains()
            dictionary.Add(e);
        }
    }

অথবা আপনি যদি কোনও মাল্টিথ্রেডেড অ্যাপ্লিকেশনটিতে কাজ করছেন এবং আপনার অভিধানটি যাহাই হউক না কেন থ্রেড নিরাপদ হওয়া দরকার, আপনার এটি করা উচিত:

    public static void MergeOverwrite<T1, T2>(this ConcurrentDictionary<T1, T2> dictionary, IDictionary<T1, T2> newElements)
    {
        if (newElements == null || newElements.Count == 0) return;

        foreach (var ne in newElements)
        {
            dictionary.AddOrUpdate(ne.Key, ne.Value, (key, value) => value);
        }
    }

এরপরে আপনি অভিধানের একটি সংখ্যা হ্যান্ডেল করার জন্য এটি মোড়ানো করতে পারেন। নির্বিশেষে, আপনি প্রায় ~ O (3n) (সমস্ত শর্ত নিখুঁত হচ্ছে) এ খুঁজছেন, যেহেতু .Add()ইচ্ছাশক্তিগুলি Contains()পর্দার আড়ালে একটি অতিরিক্ত, অপ্রয়োজনীয় কিন্তু ব্যবহারিকভাবে মুক্ত করবে। আমি মনে করি না এটি আরও ভাল হয়ে যায়।

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

    public static IDictionary<T1, T2> MergeAllOverwrite<T1, T2>(IList<IDictionary<T1, T2>> allDictionaries)
    {
        var initSize = allDictionaries.Sum(d => d.Count);
        var resultDictionary = new Dictionary<T1, T2>(initSize);
        allDictionaries.ForEach(resultDictionary.MergeOverwrite);
        return resultDictionary;
    }

মনে রাখবেন যে আমি IList<T>এই পদ্ধতিটি গ্রহণ করেছি ... বেশিরভাগ কারণেই যদি আপনি এটি গ্রহণ করেন তবে আপনি IEnumerable<T>নিজেই একই সেটটির একাধিক অঙ্কের জন্য নিজেকে উন্মুক্ত করেছেন, যদি আপনার বিলম্বিত লিংকিউ থেকে আপনার অভিধানের সংগ্রহ পাওয়া যায় তবে এটি খুব ব্যয়বহুল হতে পারে can বিবৃতি।


4

উপরের উত্তরের উপর ভিত্তি করে, তবে কলারকে সদৃশগুলি পরিচালনা করতে ফান-প্যারামিটার যুক্ত করুন:

public static Dictionary<TKey, TValue> Merge<TKey, TValue>(this IEnumerable<Dictionary<TKey, TValue>> dicts, 
                                                           Func<IGrouping<TKey, TValue>, TValue> resolveDuplicates)
{
    if (resolveDuplicates == null)
        resolveDuplicates = new Func<IGrouping<TKey, TValue>, TValue>(group => group.First());

    return dicts.SelectMany<Dictionary<TKey, TValue>, KeyValuePair<TKey, TValue>>(dict => dict)
                .ToLookup(pair => pair.Key, pair => pair.Value)
                .ToDictionary(group => group.Key, group => resolveDuplicates(group));
}

4

পার্টির এখন বেশ মারা গেছে, তবে এখানে ব্যবহারকারীর একটি "উন্নত" সংস্করণ রয়েছে যা আমার এক্সটেনশন লাইব্রেরিতে প্রবেশ করেছে। কিছু বিশদ ছাড়াও, মার্জ হওয়া মানটি গণনা করার জন্য আমি একটি প্রতিনিধি যুক্ত করেছি।

/// <summary>
/// Merges a dictionary against an array of other dictionaries.
/// </summary>
/// <typeparam name="TResult">The type of the resulting dictionary.</typeparam>
/// <typeparam name="TKey">The type of the key in the resulting dictionary.</typeparam>
/// <typeparam name="TValue">The type of the value in the resulting dictionary.</typeparam>
/// <param name="source">The source dictionary.</param>
/// <param name="mergeBehavior">A delegate returning the merged value. (Parameters in order: The current key, The current value, The previous value)</param>
/// <param name="mergers">Dictionaries to merge against.</param>
/// <returns>The merged dictionary.</returns>
public static TResult MergeLeft<TResult, TKey, TValue>(
    this TResult source,
    Func<TKey, TValue, TValue, TValue> mergeBehavior,
    params IDictionary<TKey, TValue>[] mergers)
    where TResult : IDictionary<TKey, TValue>, new()
{
    var result = new TResult();
    var sources = new List<IDictionary<TKey, TValue>> { source }
        .Concat(mergers);

    foreach (var kv in sources.SelectMany(src => src))
    {
        TValue previousValue;
        result.TryGetValue(kv.Key, out previousValue);
        result[kv.Key] = mergeBehavior(kv.Key, kv.Value, previousValue);
    }

    return result;
}

2

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

Dictionary<string, string> t1 = new Dictionary<string, string>();
t1.Add("a", "aaa");
Dictionary<string, string> t2 = new Dictionary<string, string>();
t2.Add("b", "bee");
Dictionary<string, string> t3 = new Dictionary<string, string>();
t3.Add("c", "cee");
t3.Add("d", "dee");
t3.Add("b", "bee");
Dictionary<string, string> merged = t1.MergeLeft(t2, t2, t3);

দ্রষ্টব্য: আমি @ অ্যান্ড্রু ওরিচ দ্বারা সমাধানটিতে @ ইউনাইটেড দ্বারা সংশোধনটি প্রয়োগ করেছি, সুতরাং মার্জলিফ্টটি এখন দেখতে দেখতে:

public static Dictionary<K, V> MergeLeft<K, V>(this Dictionary<K, V> me, params IDictionary<K, V>[] others)
    {
        var newMap = new Dictionary<K, V>(me, me.Comparer);
        foreach (IDictionary<K, V> src in
            (new List<IDictionary<K, V>> { me }).Concat(others))
        {
            // ^-- echk. Not quite there type-system.
            foreach (KeyValuePair<K, V> p in src)
            {
                newMap[p.Key] = p.Value;
            }
        }
        return newMap;
    }

আমি যা লিখেছি তার কাছাকাছি। এটি, ofc, কেবল Dictionaryপ্রকারের জন্য কাজ করবে । Overloads অন্যান্য অভিধান প্রকার (জন্য যোগ করা যেতে পারে ConcurrentDictionary, ReadOnlyDictionaryইত্যাদি) আমি একটি নতুন তালিকা তৈরির মনে করি না, এবং CONCAT ব্যক্তিগতভাবে প্রয়োজনীয়। আমি প্রথমে প্রথমে প্যারামের অ্যারেটি পুনরুক্ত করেছি, তারপরে প্রতিটি অভিধানের প্রতিটি কেভিপি পুনরুক্ত করেছি। আমি কোনও ড্র ফিরে দেখছি না।
ক্রাশ করুন

আপনি অভিধানের পরিবর্তে আইডি অভিধান ব্যবহার করতে পারেন
মারিউজ জামরো

আপনি Dictionaryএকটিতে এক্সটেনশন পদ্ধতিটি ব্যবহার করলেও আপনি সর্বদা একটি অবজেক্ট পেয়ে যাবেন ConcurrentDictionary। এর ফলে বাগগুলি সনাক্ত করা শক্ত হতে পারে।
মার্সেল

2

আমি জানি এটি একটি পুরানো প্রশ্ন, তবে যেহেতু এখন আমাদের কাছে লিনকিউ রয়েছে আপনি এটি একক লাইনে এটি করতে পারেন

Dictionary<T1,T2> merged;
Dictionary<T1,T2> mergee;
mergee.ToList().ForEach(kvp => merged.Add(kvp.Key, kvp.Value));

অথবা

mergee.ToList().ForEach(kvp => merged.Append(kvp));

দুঃখিত downvote @Cruces জন্য, কিন্তু আপনার প্রথম উদাহরণ উত্তর সদৃশ stackoverflow.com/a/6695211/704808 এবং আপনার দ্বিতীয় উদাহরণ মাত্র থেকে প্রতিটি আইটেমের সংযোজন পর প্রসারিত IEnumerable <KeyValuePair <স্ট্রিং, স্ট্রিং >> খারিজ রাখে mergee
weir

2

C # তে নতুন হয়ে জটিল উত্তরগুলি দেখে ভয় পেয়ে গেলেন।

এখানে কিছু সহজ উত্তর দেওয়া হল।
ডি 1, ডি 2, এবং এইভাবে .. মার্জ করে এবং কোনও ওভারল্যাপিং কী (নীচে উদাহরণগুলিতে "বি") হ্যান্ডেল করুন:

উদাহরণ 1

{
    // 2 dictionaries,  "b" key is common with different values

    var d1 = new Dictionary<string, int>() { { "a", 10 }, { "b", 21 } };
    var d2 = new Dictionary<string, int>() { { "c", 30 }, { "b", 22 } };

    var result1 = d1.Concat(d2).GroupBy(ele => ele.Key).ToDictionary(ele => ele.Key, ele => ele.First().Value);
    // result1 is  a=10, b=21, c=30    That is, took the "b" value of the first dictionary

    var result2 = d1.Concat(d2).GroupBy(ele => ele.Key).ToDictionary(ele => ele.Key, ele => ele.Last().Value);
    // result2 is  a=10, b=22, c=30    That is, took the "b" value of the last dictionary
}

উদাহরণ 2

{
    // 3 dictionaries,  "b" key is common with different values

    var d1 = new Dictionary<string, int>() { { "a", 10 }, { "b", 21 } };
    var d2 = new Dictionary<string, int>() { { "c", 30 }, { "b", 22 } };
    var d3 = new Dictionary<string, int>() { { "d", 40 }, { "b", 23 } };

    var result1 = d1.Concat(d2).Concat(d3).GroupBy(ele => ele.Key).ToDictionary(ele => ele.Key, ele => ele.First().Value);
    // result1 is  a=10, b=21, c=30, d=40    That is, took the "b" value of the first dictionary

    var result2 = d1.Concat(d2).Concat(d3).GroupBy(ele => ele.Key).ToDictionary(ele => ele.Key, ele => ele.Last().Value);
    // result2 is  a=10, b=23, c=30, d=40    That is, took the "b" value of the last dictionary
}

আরও জটিল পরিস্থিতিতে, অন্যান্য উত্তর দেখুন।
আশা করি যে সাহায্য করেছে।


2
using System.Collections.Generic;
using System.Linq;

public static class DictionaryExtensions
{
    public enum MergeKind { SkipDuplicates, OverwriteDuplicates }
    public static void Merge<K, V>(this IDictionary<K, V> target, IDictionary<K, V> source, MergeKind kind = MergeKind.SkipDuplicates) =>
        source.ToList().ForEach(_ => { if (kind == MergeKind.OverwriteDuplicates || !target.ContainsKey(_.Key)) target[_.Key] = _.Value; });
}

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


অযৌক্তিক বাইনারি এনাম ছাড়াই নীচে
পরিশ্রুত

2

মনে রাখবেন যে আপনি যদি 'অ্যাড' নামক একটি এক্সটেনশন পদ্ধতি ব্যবহার করেন তবে সংগ্রহের সূচনাযন্ত্র ব্যবহার করতে হবে যতগুলি প্রয়োজন ঠিক তেমন অভিধানকে একত্রিত করতে:

public static void Add<K, V>(this Dictionary<K, V> d, Dictionary<K, V> other) {
  foreach (var kvp in other)
  {
    if (!d.ContainsKey(kvp.Key))
    {
      d.Add(kvp.Key, kvp.Value);
    }
  }
}


var s0 = new Dictionary<string, string> {
  { "A", "X"}
};
var s1 = new Dictionary<string, string> {
  { "A", "X" },
  { "B", "Y" }
};
// Combine as many dictionaries and key pairs as needed
var a = new Dictionary<string, string> {
  s0, s1, s0, s1, s1, { "C", "Z" }
};

1

একটি এক্সটেনশন পদ্ধতি ব্যবহার করে মার্জ করা হচ্ছে। সদৃশ কী থাকলে এটি ব্যতিক্রম হয় না, তবে দ্বিতীয় অভিধান থেকে কীগুলি দিয়ে কীগুলি প্রতিস্থাপন করে।

internal static class DictionaryExtensions
{
    public static Dictionary<T1, T2> Merge<T1, T2>(this Dictionary<T1, T2> first, Dictionary<T1, T2> second)
    {
        if (first == null) throw new ArgumentNullException("first");
        if (second == null) throw new ArgumentNullException("second");

        var merged = new Dictionary<T1, T2>();
        first.ToList().ForEach(kv => merged[kv.Key] = kv.Value);
        second.ToList().ForEach(kv => merged[kv.Key] = kv.Value);

        return merged;
    }
}

ব্যবহার:

Dictionary<string, string> merged = first.Merge(second);

1

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

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

public static partial class Extensions
{
    public static void Merge<K, V>(this IDictionary<K, V> target, IDictionary<K, V> source, bool overwrite = false)
    {
        source.ToList().ForEach(_ => {
            if ((!target.ContainsKey(_.Key)) || overwrite)
                target[_.Key] = _.Value;
        });
    }
}

0

EqualityComparerআলাদা মান / প্রকারের সাথে তুলনা করার জন্য আইটেমকে মানচিত্র করে এমনটি ব্যবহার করে মার্জ করা । এখানে আমরা KeyValuePair(অভিধান গণনার সময় আইটেমের ধরণ) থেকে ম্যাপ করব Key

public class MappedEqualityComparer<T,U> : EqualityComparer<T>
{
    Func<T,U> _map;

    public MappedEqualityComparer(Func<T,U> map)
    {
        _map = map;
    }

    public override bool Equals(T x, T y)
    {
        return EqualityComparer<U>.Default.Equals(_map(x), _map(y));
    }

    public override int GetHashCode(T obj)
    {
        return _map(obj).GetHashCode();
    }
}

ব্যবহার:

// if dictA and dictB are of type Dictionary<int,string>
var dict = dictA.Concat(dictB)
                .Distinct(new MappedEqualityComparer<KeyValuePair<int,string>,int>(item => item.Key))
                .ToDictionary(item => item.Key, item=> item.Value);

0

বা:

public static IDictionary<TKey, TValue> Merge<TKey, TValue>( IDictionary<TKey, TValue> x, IDictionary<TKey, TValue> y)
    {
        return x
            .Except(x.Join(y, z => z.Key, z => z.Key, (a, b) => a))
            .Concat(y)
            .ToDictionary(z => z.Key, z => z.Value);
    }

ফলাফলটি এমন একটি ইউনিয়ন যেখানে সদৃশ এন্ট্রিগুলির জন্য "y" জয়লাভ করে।


0
public static IDictionary<K, V> AddRange<K, V>(this IDictionary<K, V> one, IDictionary<K, V> two)
        {
            foreach (var kvp in two)
            {
                if (one.ContainsKey(kvp.Key))
                    one[kvp.Key] = two[kvp.Key];
                else
                    one.Add(kvp.Key, kvp.Value);
            }
            return one;
        }

0

সংক্ষিপ্ত IEqualityComparerকী কী তুলনা করার জন্য @ ব্যবহারকারী 166390 এর একটি সংস্করণ একটি যুক্ত পরামিতি সহ উত্তর answer

    public static T MergeLeft<T, K, V>(this T me, params Dictionary<K, V>[] others)
        where T : Dictionary<K, V>, new()
    {
        return me.MergeLeft(me.Comparer, others);
    }

    public static T MergeLeft<T, K, V>(this T me, IEqualityComparer<K> comparer, params Dictionary<K, V>[] others)
        where T : Dictionary<K, V>, new()
    {
        T newMap = Activator.CreateInstance(typeof(T), new object[] { comparer }) as T;

        foreach (Dictionary<K, V> src in 
            (new List<Dictionary<K, V>> { me }).Concat(others))
        {
            // ^-- echk. Not quite there type-system.
            foreach (KeyValuePair<K, V> p in src)
            {
                newMap[p.Key] = p.Value;
            }
        }
        return newMap;
    }

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.