জেনেরিক অভিধানের নির্দিষ্ট মানটির একাধিক কী পাচ্ছেন?


122

.NET জেনেরিক অভিধান থেকে কোনও কীটির মান পাওয়া সহজ:

Dictionary<int, string> greek = new Dictionary<int, string>();
greek.Add(1, "Alpha");
greek.Add(2, "Beta");
string secondGreek = greek[2];  // Beta

তবে কীগুলি একটি মান দেওয়ার চেষ্টা করা তত সোজা নয়, কারণ একাধিক কী থাকতে পারে:

int[] betaKeys = greek.WhatDoIPutHere("Beta");  // expecting single 2

1
int[]আপনি যখন একক মান আশা করেন তবে রিটার্নের ধরণটি কেন হয়?
আনার খলিলভ

3
@ আনার, ডোমেনিকের প্রতি আমার উত্তরটি পড়ুন; "সদৃশ মানগুলি অসম্ভব তবে অসম্ভব নয়"।
ডোর হাই আর্চ

একটি মান কী? আমি মনে করি আপনি কীগুলি
ম্যাক্স হজস

উত্তর:


144

ঠিক আছে, এখানে একাধিক দ্বিদলীয় সংস্করণ:

using System;
using System.Collections.Generic;
using System.Text;

class BiDictionary<TFirst, TSecond>
{
    IDictionary<TFirst, IList<TSecond>> firstToSecond = new Dictionary<TFirst, IList<TSecond>>();
    IDictionary<TSecond, IList<TFirst>> secondToFirst = new Dictionary<TSecond, IList<TFirst>>();

    private static IList<TFirst> EmptyFirstList = new TFirst[0];
    private static IList<TSecond> EmptySecondList = new TSecond[0];

    public void Add(TFirst first, TSecond second)
    {
        IList<TFirst> firsts;
        IList<TSecond> seconds;
        if (!firstToSecond.TryGetValue(first, out seconds))
        {
            seconds = new List<TSecond>();
            firstToSecond[first] = seconds;
        }
        if (!secondToFirst.TryGetValue(second, out firsts))
        {
            firsts = new List<TFirst>();
            secondToFirst[second] = firsts;
        }
        seconds.Add(second);
        firsts.Add(first);
    }

    // Note potential ambiguity using indexers (e.g. mapping from int to int)
    // Hence the methods as well...
    public IList<TSecond> this[TFirst first]
    {
        get { return GetByFirst(first); }
    }

    public IList<TFirst> this[TSecond second]
    {
        get { return GetBySecond(second); }
    }

    public IList<TSecond> GetByFirst(TFirst first)
    {
        IList<TSecond> list;
        if (!firstToSecond.TryGetValue(first, out list))
        {
            return EmptySecondList;
        }
        return new List<TSecond>(list); // Create a copy for sanity
    }

    public IList<TFirst> GetBySecond(TSecond second)
    {
        IList<TFirst> list;
        if (!secondToFirst.TryGetValue(second, out list))
        {
            return EmptyFirstList;
        }
        return new List<TFirst>(list); // Create a copy for sanity
    }
}

class Test
{
    static void Main()
    {
        BiDictionary<int, string> greek = new BiDictionary<int, string>();
        greek.Add(1, "Alpha");
        greek.Add(2, "Beta");
        greek.Add(5, "Beta");
        ShowEntries(greek, "Alpha");
        ShowEntries(greek, "Beta");
        ShowEntries(greek, "Gamma");
    }

    static void ShowEntries(BiDictionary<int, string> dict, string key)
    {
        IList<int> values = dict[key];
        StringBuilder builder = new StringBuilder();
        foreach (int value in values)
        {
            if (builder.Length != 0)
            {
                builder.Append(", ");
            }
            builder.Append(value);
        }
        Console.WriteLine("{0}: [{1}]", key, builder);
    }
}

2
আমি এমএসডিএন-তে যা পড়েছি তা থেকে, এটি কোনও বাইড অভিধানের পরিবর্তে বায়লুকআপ হওয়া উচিত নয়? এটি গুরুত্বপূর্ণ বা কোনও কিছু নয়, আমি যদি বিষয়গুলি এখানে সঠিকভাবে বুঝতে পারি তবে কেবল কৌতূহলী ...
Svish

এছাড়াও, আমি গেটবাই ফার্স্ট ব্যবহার করেছি এবং এম্পটিসেকেন্ডলিস্টটি ফিরে পেয়েছি, এতে কিছু জিনিস যুক্ত করেছি এবং তারপরে আবার গেটবাই ফার্স্ট বলেছি, আমি কি এতে কিছু জিনিস সহ একটি তালিকা পাব না এবং তখন খালি তালিকা না করে থাকব?
Svish

@ সুইশ: না, কারণ আপনি যখন তালিকায় যুক্ত করার চেষ্টা করেছিলেন তখন এটি ব্যতিক্রম হয় (আপনি কোনও অ্যারেতে যোগ করতে পারবেন না)। এবং হ্যাঁ, বিলুকআপ সম্ভবত আরও ভাল নাম হবে।
জন স্কিটি

আমি যখন ওপির প্রশ্নের উত্তরগুলি দেখতে পাচ্ছি, এটি কি কিছুটা নিষ্পাপ বাস্তবায়ন নয়? ডিকশনারি <> তালিকা <> অভিধানে এর চেয়ে আরও বাস্তবসম্মত বাস্তবায়ন হবে না যাতে আপনি 2 টি ভিন্ন কী দ্বারা বাস্তবে সমৃদ্ধ বস্তুগুলি সন্ধান করতে পারেন?
ক্রিস মেরিসিক

@ ক্রিসমারিসিক: আপনি কী বোঝাতে চাইছেন তা নিশ্চিত নন - তবে এরকম কিছু যা আমি বেশ খানিকটা ব্যবহার করেছি এবং এর চেয়ে বেশি কিছু প্রয়োজন নেই not
জন স্কিটি

74

যেমনটি সবাই বলেছে, অভিধান থেকে মান থেকে কী পর্যন্ত কোনও ম্যাপিং নেই।

আমি সবেমাত্র লক্ষ্য করেছি যে আপনি মান থেকে একাধিক কীতে মানচিত্র তৈরি করতে চেয়েছিলেন - আমি একক মান সংস্করণের জন্য এই সমাধানটি এখানে রেখে দিচ্ছি, তবে আমি মাল্টি-এন্ট্রি দ্বিদলীয় মানচিত্রের জন্য আরও একটি উত্তর যুক্ত করব।

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

using System;
using System.Collections.Generic;

class BiDictionary<TFirst, TSecond>
{
    IDictionary<TFirst, TSecond> firstToSecond = new Dictionary<TFirst, TSecond>();
    IDictionary<TSecond, TFirst> secondToFirst = new Dictionary<TSecond, TFirst>();

    public void Add(TFirst first, TSecond second)
    {
        if (firstToSecond.ContainsKey(first) ||
            secondToFirst.ContainsKey(second))
        {
            throw new ArgumentException("Duplicate first or second");
        }
        firstToSecond.Add(first, second);
        secondToFirst.Add(second, first);
    }

    public bool TryGetByFirst(TFirst first, out TSecond second)
    {
        return firstToSecond.TryGetValue(first, out second);
    }

    public bool TryGetBySecond(TSecond second, out TFirst first)
    {
        return secondToFirst.TryGetValue(second, out first);
    }
}

class Test
{
    static void Main()
    {
        BiDictionary<int, string> greek = new BiDictionary<int, string>();
        greek.Add(1, "Alpha");
        greek.Add(2, "Beta");
        int x;
        greek.TryGetBySecond("Beta", out x);
        Console.WriteLine(x);
    }
}

1
আমি মনে করি না যে এটি একটি কংক্রিট শ্রেণি থেকে প্রাপ্ত করার কোনও কারণ আছে - আমি খুব যত্ন সহকারে চিন্তা না করে উত্তরাধিকার পছন্দ করি না - তবে এটি অবশ্যই মূল পরিমাণে বাস্তবায়ন করতে পারে ইত্যাদি। বাস্তবে, এটি আইডিয়োরিয়াল <টিফারস্ট, টিসেকেন্ড> এবং আইডিকোরিয়াস বাস্তবায়ন করতে পারে <টি সেকেন্ড, টিফারস্ট>।
জন স্কিটি

1
(যদিও টিফার্স্ট এবং টি সেকেন্ড একই রকম হয় তবে তা বেশ অদ্ভুত হবে ...)
জন স্কিটি

6
বাস্তবে আপনি <টিফার্স্ট, টিসেকন্ড> এবং আইডিয়োরিজ <টি সেকেন্ড, টিফারস্ট> উভয়ই একই প্রয়োগ করতে পারবেন না, নেট 4.0 এটি অনুমোদন দেয় না
সেবাস্তিয়ান

2
@nawfal: এক অভিধানের Addকল ব্যর্থ হবে - কিন্তু যদি এটা দ্বিতীয়, আমরা তারপর একটি বিভ্রান্ত দশায় সিস্টেম পেয়েছেন। আমার উপায়, আপনি এখনও ব্যতিক্রম পরে একটি সামঞ্জস্যপূর্ণ সংগ্রহ আছে।
জন স্কিটি

1
@ নওফাল: আচ্ছা আমি জানি না যে কারণ আমি যখন প্রথম উত্তরটি লিখলাম তখনই আমি এটি করেছি কি না ... আমি অনুমান করছি;)
জন স্কিচ ২৯'১৩

26

অভিধানগুলি আসলে এর মতো কাজ করে বোঝানো হয় না, কারণ কীগুলির স্বতন্ত্রতা নিশ্চিত হওয়ার পরেও মানগুলির স্বতন্ত্রতা নয় isn't সুতরাং যেমন আপনি যদি

var greek = new Dictionary<int, string> { { 1, "Alpha" }, { 2, "Alpha" } };

আপনি কি পেতে আশা করবেন greek.WhatDoIPutHere("Alpha")?

অতএব আপনি ফ্রেমওয়ার্কে ঘূর্ণিত হয়ে যাওয়ার মতো কিছু আশা করতে পারবেন না। আপনার নিজস্ব অনন্য ব্যবহারের জন্য আপনার নিজস্ব পদ্ধতি দরকার --- আপনি কি কোনও অ্যারে (বা IEnumerable<T>) ফিরিয়ে দিতে চান ? প্রদত্ত মানটির সাথে একাধিক কী থাকলে আপনি কি একটি ব্যতিক্রম নিক্ষেপ করতে চান? কেউ না থাকলে কি হবে?

ব্যক্তিগতভাবে আমি একটি গণনার জন্য যেতে চাই, যেমন:

IEnumerable<TKey> KeysFromValue<TKey, TValue>(this Dictionary<TKey, TValue> dict, TValue val)
{
    if (dict == null)
    {
        throw new ArgumentNullException("dict");
    }
    return dict.Keys.Where(k => dict[k] == val);
}

var keys = greek.KeysFromValue("Beta");
int exceptionIfNotExactlyOne = greek.KeysFromValue("Beta").Single();

একটি মার্জিত সমাধান, তবে এটি অবশ্যই 2.0 তে কাজ করবে। সদৃশ মানগুলি অসম্ভব তবে অসম্ভব নয়, কোনও সংগ্রহ ফেরত দেওয়া ভাল।
ডোর হাই আর্চ

23

লিনক ব্যতীত এটি করার সহজতম উপায়টি জোড়গুলির উপর লুপ করা যেতে পারে:

int betaKey; 
foreach (KeyValuePair<int, string> pair in lookup)
{
    if (pair.Value == value)
    {
        betaKey = pair.Key; // Found
        break;
    }
}
betaKey = -1; // Not found

যদি আপনার লিঙ্ক থাকে তবে এটি সহজেই এটি করতে পারত:

int betaKey = greek.SingleOrDefault(x => x.Value == "Beta").Key;

ঘুরে বেড়াও, তবে আপনার উপরে একটি ভেরি টাইপ আছে ?! অবশ্যই আপনি 3.0 এ আছেন? নীচে আমার আপডেট দেখুন।
কবুতর

দুঃখিত, আমি টাইপিং হ্রাস করার জন্য "ভার" ব্যবহার করেছি। আমি লিনিয়ার অনুসন্ধান না করাকে পছন্দ করব, অভিধানটি বড় হতে পারে।
ডোর হাই আর্চ

2
varএকটি ভাষা বৈশিষ্ট্য, কাঠামোর বৈশিষ্ট্য নয়। আপনি সি # -6.0 থেকে নাল-কোলেসিং ব্যবহার করতে পারেন এবং আপনি যদি সত্যিই চান তবে সিএফ -০.০ লক্ষ্যবস্তু করতে পারেন।
বিনিকি

3

একটি অভিধান মানগুলির একটি হ্যাশ রাখে না, কেবল কীগুলি তাই কোনও মান ব্যবহার করে এর উপর অনুসন্ধান করা কমপক্ষে রৈখিক সময় নিতে চলেছে। আপনার সেরা বাজিটি হ'ল অভিধানে থাকা উপাদানগুলির উপর সহজেই পুনরাবৃত্তি করা এবং ম্যাচিং কীগুলি অনুসরণ করা বা কোনও অন্য ডেটা স্ট্রাকচারে স্যুইচ করা, সম্ভবত দুটি অভিধান ম্যাপিং কী-> মান এবং মান-> তালিকা_ফেস_কে বজায় রাখা। আপনি যদি এটি করেন তবে আপনি দ্রুত গতির জন্য স্টোরেজ বাণিজ্য করবেন। @ সাইবাইস উদাহরণটিকে এই জাতীয় ডেটা কাঠামোতে রূপান্তর করতে খুব বেশি লাগবে না।


3

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

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Common
{
    /// <summary>Represents a bidirectional collection of keys and values.</summary>
    /// <typeparam name="TFirst">The type of the keys in the dictionary</typeparam>
    /// <typeparam name="TSecond">The type of the values in the dictionary</typeparam>
    [System.Runtime.InteropServices.ComVisible(false)]
    [System.Diagnostics.DebuggerDisplay("Count = {Count}")]
    //[System.Diagnostics.DebuggerTypeProxy(typeof(System.Collections.Generic.Mscorlib_DictionaryDebugView<,>))]
    //[System.Reflection.DefaultMember("Item")]
    public class BiDictionary<TFirst, TSecond> : Dictionary<TFirst, TSecond>
    {
        IDictionary<TSecond, TFirst> _ValueKey = new Dictionary<TSecond, TFirst>();
        /// <summary> PropertyAccessor for Iterator over KeyValue-Relation </summary>
        public IDictionary<TFirst, TSecond> KeyValue => this;
        /// <summary> PropertyAccessor for Iterator over ValueKey-Relation </summary>
        public IDictionary<TSecond, TFirst> ValueKey => _ValueKey;

        #region Implemented members

        /// <Summary>Gets or sets the value associated with the specified key.</Summary>
        /// <param name="key">The key of the value to get or set.</param>
        /// <Returns>The value associated with the specified key. If the specified key is not found,
        ///      a get operation throws a <see cref="KeyNotFoundException"/>, and
        ///      a set operation creates a new element with the specified key.</Returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.</exception>
        /// <exception cref="T:System.Collections.Generic.KeyNotFoundException">
        /// The property is retrieved and <paramref name="key"/> does not exist in the collection.</exception>
        /// <exception cref="T:System.ArgumentException"> An element with the same key already
        /// exists in the <see cref="ValueKey"/> <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</exception>
        public new TSecond this[TFirst key]
        {
            get { return base[key]; }
            set { _ValueKey.Remove(base[key]); base[key] = value; _ValueKey.Add(value, key); }
        }

        /// <Summary>Gets or sets the key associated with the specified value.</Summary>
        /// <param name="val">The value of the key to get or set.</param>
        /// <Returns>The key associated with the specified value. If the specified value is not found,
        ///      a get operation throws a <see cref="KeyNotFoundException"/>, and
        ///      a set operation creates a new element with the specified value.</Returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="val"/> is null.</exception>
        /// <exception cref="T:System.Collections.Generic.KeyNotFoundException">
        /// The property is retrieved and <paramref name="val"/> does not exist in the collection.</exception>
        /// <exception cref="T:System.ArgumentException"> An element with the same value already
        /// exists in the <see cref="KeyValue"/> <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</exception>
        public TFirst this[TSecond val]
        {
            get { return _ValueKey[val]; }
            set { base.Remove(_ValueKey[val]); _ValueKey[val] = value; base.Add(value, val); }
        }

        /// <Summary>Adds the specified key and value to the dictionary.</Summary>
        /// <param name="key">The key of the element to add.</param>
        /// <param name="value">The value of the element to add.</param>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="key"/> or <paramref name="value"/> is null.</exception>
        /// <exception cref="T:System.ArgumentException">An element with the same key or value already exists in the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</exception>
        public new void Add(TFirst key, TSecond value) {
            base.Add(key, value);
            _ValueKey.Add(value, key);
        }

        /// <Summary>Removes all keys and values from the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</Summary>
        public new void Clear() { base.Clear(); _ValueKey.Clear(); }

        /// <Summary>Determines whether the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/> contains the specified
        ///      KeyValuePair.</Summary>
        /// <param name="item">The KeyValuePair to locate in the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</param>
        /// <Returns>true if the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/> contains an element with
        ///      the specified key which links to the specified value; otherwise, false.</Returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="item"/> is null.</exception>
        public bool Contains(KeyValuePair<TFirst, TSecond> item) => base.ContainsKey(item.Key) & _ValueKey.ContainsKey(item.Value);

        /// <Summary>Removes the specified KeyValuePair from the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</Summary>
        /// <param name="item">The KeyValuePair to remove.</param>
        /// <Returns>true if the KeyValuePair is successfully found and removed; otherwise, false. This
        ///      method returns false if <paramref name="item"/> is not found in the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</Returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="item"/> is null.</exception>
        public bool Remove(KeyValuePair<TFirst, TSecond> item) => base.Remove(item.Key) & _ValueKey.Remove(item.Value);

        /// <Summary>Removes the value with the specified key from the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</Summary>
        /// <param name="key">The key of the element to remove.</param>
        /// <Returns>true if the element is successfully found and removed; otherwise, false. This
        ///      method returns false if <paramref name="key"/> is not found in the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</Returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.</exception>
        public new bool Remove(TFirst key) => _ValueKey.Remove(base[key]) & base.Remove(key);

        /// <Summary>Gets the key associated with the specified value.</Summary>
        /// <param name="value">The value of the key to get.</param>
        /// <param name="key">When this method returns, contains the key associated with the specified value,
        ///      if the value is found; otherwise, the default value for the type of the key parameter.
        ///      This parameter is passed uninitialized.</param>
        /// <Returns>true if <see cref="ValueKey"/> contains an element with the specified value; 
        ///      otherwise, false.</Returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="value"/> is null.</exception>
        public bool TryGetValue(TSecond value, out TFirst key) => _ValueKey.TryGetValue(value, out key);
        #endregion
    }
}

2

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

এটি বলেছিল দেখে মনে হচ্ছে আপনি সি # 3.0 ব্যবহার করছেন যাতে আপনাকে লুপিংয়ের আশ্রয় নিতে না হয় এবং এর মতো কিছু ব্যবহার করতে পারে:

var key = (from k in yourDictionary where string.Compare(k.Value, "yourValue", true)  == 0 select k.Key).FirstOrDefault();

অভিধান নেই .FindByValue। আমি মানগুলির চেয়ে লুপের চেয়ে আলাদা ডেটা স্ট্রাকচারে চলে যেতে চাই।
ডোর হাই আর্চ

2

অভিধানের ক্লাসটি এই ক্ষেত্রেটির জন্য অনুকূলিত করা হয়নি, তবে আপনি যদি সত্যিই এটি করতে চান (সি # 2.0 তে), আপনি এটি করতে পারেন:

public List<TKey> GetKeysFromValue<TKey, TVal>(Dictionary<TKey, TVal> dict, TVal val)
{
   List<TKey> ks = new List<TKey>();
   foreach(TKey k in dict.Keys)
   {
      if (dict[k] == val) { ks.Add(k); }
   }
   return ks;
}

আমি কমনীয়তার জন্য লিনকিউ সমাধানটি পছন্দ করি তবে এটি 2.0 উপায় way


1

আপনি কি অভিধানের একটি সাবক্লাস তৈরি করতে পারবেন না যার সেই কার্যকারিতা রয়েছে?


    public class MyDict < TKey, TValue > : Dictionary < TKey, TValue >
    {
        private Dictionary < TValue, TKey > _keys;

        public TValue this[TKey key]
        {
            get
            {
                return base[key];
            }
            set 
            { 
                base[key] = value;
                _keys[value] = key;
            }
        }

        public MyDict()
        {
            _keys = new Dictionary < TValue, TKey >();
        }

        public TKey GetKeyFromValue(TValue value)
        {
            return _keys[value];
        }
    }

সম্পাদনা: দুঃখিত, প্রথমবারের মতো কোড পেলেন না।


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

যদি আপনার ইনট কীগুলির জন্য সদৃশ স্ট্রিং মান থাকতে পারে তবে আপনি স্ট্রিং-এ সন্ধানের পরে কী ফিরে আসবেন বলে আশা করেন? সংশ্লিষ্ট ইন এর একটি তালিকা অবজেক্ট?
সাইবিস

1

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

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


অথবা সম্ভবত একটি দ্বিতীয় অভিধান যা প্রতিটি মানকে এর কী (গুলি) এ ম্যাপ করে।
ডেভিডআরআর

@ ডেভিডআরআর কেবল কীগুলি অবশ্যই অনন্য হতে হবে, সুতরাং দ্বিতীয় অভিধানের পদ্ধতিটি সত্যিই কাজ করবে না। অভিধানের কোনও মূল্যের জন্য কীগুলি পাওয়া গেলেও আপনি কেবল লুপ করতে পারেন।
ম্যাক্স হজস

একটি অভিধান জন্য সমস্যা কল একাধিক সমর্থন করার জন্য যদি intপ্রতি মান stringকী, তারপর অভিধান ভালো সংজ্ঞায়িত করা যেতে পারে: Dictionary<string, List<int>>
ডেভিডআরআর

এখন পুনরাবৃত্তি না করে কীভাবে দ্বিদ্বৈতিক করবেন?
ম্যাক্স

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

1

বিপরীত অনুসন্ধান করতে লিনকিউ ব্যবহার করুন Dictionary<K, V>। তবে মনে রাখবেন যে আপনার Dictionary<K, V>মানগুলির মানগুলি পৃথক নাও হতে পারে।

প্রদর্শন:

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

class ReverseDictionaryLookupDemo
{
    static void Main()
    {
        var dict = new Dictionary<int, string>();
        dict.Add(4, "Four");
        dict.Add(5, "Five");
        dict.Add(1, "One");
        dict.Add(11, "One"); // duplicate!
        dict.Add(3, "Three");
        dict.Add(2, "Two");
        dict.Add(44, "Four"); // duplicate!

        Console.WriteLine("\n== Enumerating Distinct Values ==");
        foreach (string value in dict.Values.Distinct())
        {
            string valueString =
                String.Join(", ", GetKeysFromValue(dict, value));

            Console.WriteLine("{0} => [{1}]", value, valueString);
        }
    }

    static List<int> GetKeysFromValue(Dictionary<int, string> dict, string value)
    {
        // Use LINQ to do a reverse dictionary lookup.
        // Returns a 'List<T>' to account for the possibility
        // of duplicate values.
        return
            (from item in dict
             where item.Value.Equals(value)
             select item.Key).ToList();
    }
}

প্রত্যাশিত আউটপুট:

== Enumerating Distinct Values ==
Four => [4, 44]
Five => [5]
One => [1, 11]
Three => [3]
Two => [2]

1
সমস্যাটি আমি এর সাথে দেখতে পাচ্ছি হ'ল বিপরীত দিকনির্দেশ পেতে আপনি অভিধানের প্রতিটি উপাদান পরীক্ষা করছেন checking একটি ও (এন) অনুসন্ধানের সময় অভিধান ব্যবহারের উদ্দেশ্যকে পরাস্ত করে; এটি ও (1) হওয়া উচিত।
স্টেফেন

@ স্টেফেন - একমত অন্যরা যেমন উল্লেখ করেছে যে, কর্মক্ষমতা যদি সর্বজনীন হয় তবে মানগুলির জন্য একটি পৃথক অভিধান বা দ্বি-দিকনির্দেশক অভিধান উপযুক্ত হবে। তবে, যদি কোনও মান সন্ধান করার প্রয়োজনটি খুব কম হয় এবং তা করার ক্ষেত্রে পারফরম্যান্স গ্রহণযোগ্য হয়, তবে আমি এখানে যে রূপরেখাটি উল্লেখ করেছি তা বিবেচনার জন্য উপযুক্ত হতে পারে। এটি বলেছে যে, আমার উত্তরে লিনকিউয়ের ব্যবহার .NET 2.0 এর সাথে উপযুক্ত এমন কোনও সমাধানের জন্য ওপি'র ইচ্ছাটির সাথে সামঞ্জস্য নয়। (যদিও .NET 2.0 প্রতিবন্ধকতা 2014 সালে
তর্কযোগ্যভাবে

1
Dictionary<string, string> dic = new Dictionary<string, string>();
dic["A"] = "Ahmed";
dic["B"] = "Boys";

foreach (string mk in dic.Keys)
{
    if(dic[mk] == "Ahmed")
    {
        Console.WriteLine("The key that contains \"Ahmed\" is " + mk);
    }
}

1
একটি উত্তর পোস্ট করার জন্য ধন্যবাদ! একটি কোড স্নিপেট এই প্রশ্নের উত্তর দিতে পারত যদিও চারপাশে কিছু সংখ্যক তথ্য যুক্ত করা, যেমন ব্যাখ্যা ইত্যাদি যোগ করা এখনও দুর্দান্ত
j0k

0

গৃহীত উত্তরের একটি টুইস্ট হিসাবে ( https://stackoverflow.com/a/255638/986160 ) ধরে নিচ্ছি যে কীগুলি অভিধানে সাইনেল মানগুলির সাথে যুক্ত হবে। ( Https://stackoverflow.com/a/255630/986160 ) এর মতো তবে কিছুটা মার্জিত। অভিনবত্বটি হ'ল গ্রাহক শ্রেণি একটি গণনা বিকল্প হিসাবে ব্যবহার করা যেতে পারে (তবে স্ট্রিংগুলির জন্যও) এবং অভিধানটি আইমনামেবল প্রয়োগ করে।

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

namespace MyApp.Dictionaries
{

    class BiDictionary<TFirst, TSecond> : IEnumerable
    {
        IDictionary<TFirst, TSecond> firstToSecond = new Dictionary<TFirst, TSecond>();
        IDictionary<TSecond, TFirst> secondToFirst = new Dictionary<TSecond, TFirst>();

        public void Add(TFirst first, TSecond second)
        {
            firstToSecond.Add(first, second);
            secondToFirst.Add(second, first);
        }

        public TSecond this[TFirst first]
        {
            get { return GetByFirst(first); }
        }

        public TFirst this[TSecond second]
        {
            get { return GetBySecond(second); }
        }

        public TSecond GetByFirst(TFirst first)
        {
            return firstToSecond[first];
        }

        public TFirst GetBySecond(TSecond second)
        {
            return secondToFirst[second];
        }

        public IEnumerator GetEnumerator()
        {
            return GetFirstEnumerator();
        }

        public IEnumerator GetFirstEnumerator()
        {
            return firstToSecond.GetEnumerator();
        }

        public IEnumerator GetSecondEnumerator()
        {
            return secondToFirst.GetEnumerator();
        }
    }
}

এবং একটি গ্রাহক শ্রেণি হিসাবে আপনি থাকতে পারে

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

namespace MyApp.Dictionaries
{
    class Greek
    {

        public static readonly string Alpha = "Alpha";
        public static readonly string Beta = "Beta";
        public static readonly string Gamma = "Gamma";
        public static readonly string Delta = "Delta";


        private static readonly BiDictionary<int, string> Dictionary = new BiDictionary<int, string>();


        static Greek() {
            Dictionary.Add(1, Alpha);
            Dictionary.Add(2, Beta);
            Dictionary.Add(3, Gamma);
            Dictionary.Add(4, Delta);
        }

        public static string getById(int id){
            return Dictionary.GetByFirst(id);
        }

        public static int getByValue(string value)
        {
            return Dictionary.GetBySecond(value);
        }

    }
}

1
এটি মূলত ছয় বছর আগে পোস্ট করা উত্তর হিসাবে একই এবং ততক্ষণে উল্লিখিত হিসাবে, কীগুলি একক মানগুলির সাথে সম্পর্কিত নয়। প্রতিটি কী একাধিক মান থাকতে পারে।
ডোর হাই আর্চ

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

0

তারপরে সাধারণ মানুষের সমাধান

নীচের মত একটি ফাংশন যেমন একটি অভিধান তৈরি করা যেতে পারে:

    public Dictionary<TValue, TKey> Invert(Dictionary<TKey, TValue> dict) {
    Dictionary<TValue, TKey> ret = new Dictionary<TValue, TKey>();
    foreach (var kvp in dict) {ret[kvp.value] = kvp.key;} return ret; }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.