DuplicateDictionary – O clasă de tip dicționar care permite duplicate (Revizuirea codului, C#, Harta Hash)

hexagonest a intrebat.
a intrebat.

Din moment ce nu am găsit niciun răspuns bun, mi-am făcut propria clasă numită DuplicateDictionary pentru uz personal. Aș dori câteva sfaturi pentru a o îmbunătăți.

public class DuplicateDictionary<TKey, TValue>: List<KeyValuePair<TKey, TValue>>
{
    public DuplicateDictionary()
    {

    }

    public DuplicateDictionary(List<KeyValuePair<TKey, TValue>> list)
    {
        foreach(KeyValuePair<TKey, TValue> kvp in list)
        {
            this.Add(kvp);
        }
    }

    public DuplicateDictionary(Dictionary<TKey, TValue> dictionary)
    {
        foreach(KeyValuePair<TKey, TValue> kvp in dictionary)
        {
            this.Add(kvp);
        }
    }

    public TValue this[TKey index]
    {
        get
        {
            this.ContainsKey(index);
            return this[index];
        }
        set
        {
            this[index] = value;
        }
    }

    public void Add(TKey key, TValue value)
    {
        this.Add(new KeyValuePair<TKey, TValue>(key, value));
    }

    public bool ContainsKey(TKey key)
    {
        foreach(KeyValuePair<TKey, TValue> kvp in this)
            if(kvp.Key.Equals(key)) return true;

        return false;
    }
}

Această clasă este utilă pentru lucruri de log. Eu o folosesc pentru a înregistra funcțiile și numerele trecute ale unui calculator și, odată ce se apasă egal, adaugă toate numerele trecute cu funcțiile.

Comentarii

  • Cred că ar trebui să oferiți un exemplu despre cum ar trebui să folosească some1 această clasă. Cum veți accesa valorile duplicate? Dacă nu poți, atunci de ce să le stochezi? De asemenea, indexorul dvs. arată într-adevăr suspect.-  > Por Nikita B.
  • Consultați editarea.  > Por hexagonest.
5 răspunsuri
dcastro

O astfel de structură de date există deja și se numește ILookup<TKey, TElement>. Poate fi creată cu ajutorul funcției ToLookup extensie.

Adresa ToLookup<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>) returnează un Lookup<TKey, TElement>, un dicționar unu-la-mulțime care mapează cheile la colecții de valori. A Lookup<TKey, TElement> diferă de un Dictionary<TKey, TValue>care realizează o corespondență unu-la-unu a cheilor cu valori unice.

var list = new List<Tuple<string, int>>
{
    Tuple.Create("a", 1),
    Tuple.Create("a", 2),
    Tuple.Create("a", 3),
    Tuple.Create("b", 4),
    Tuple.Create("c", 5)
};

var lookup = list.ToLookup(t => t.Item1, t => t.Item2);

foreach(var kv in lookup)
{
    Console.Write(kv.Key);
    Console.WriteLine(" - " + string.Join(", ", kv));
}

// prints
// a - 1, 2, 3
// b - 4
// c - 5

După cum a subliniat Vince, metoda DuplicateDictionary va suferi din cauza accesului lent. Lookup nu va avea.

Heslacher

În primul rând, susțin ceea ce a afirmat Vince Panuccio în răspunsul său

Nu cred că această clasă ar trebui să aibă un motiv să existe. O cheie este doar atât, o cheie. Dacă aveți chei duplicate și valori duplicate, ceea ce căutați în esență este o grupare sau un dicționar sau cu un set sau o listă ca valoare.


Alertă de eroare

Acest lucru se va întrerupe în cazul unui StackOverflowException

public TValue this[TKey index]
{
    get
    {
        this.ContainsKey(index);
        return this[index];
    }
    set
    {
        this[index] = value;
    }
}  

prin apelarea this.ContainsKey() care se referă din nou la Item (this[TKey]), iar dacă am omite acest apel, se va întrerupe din nou cu un StackOverflowException pe baza proprietății return this[index]; care se referă din nou la obținerea proprietății în sine.

Lăsând deoparte acest mare eroare, un argument numit index indică de obicei un tip numeric. Așadar, un nume de parametru mai bun ar fi în acest caz doar key.


Ctor

public DuplicateDictionary(List<KeyValuePair<TKey, TValue>> list)
{
    foreach(KeyValuePair<TKey, TValue> kvp in list)
    {
        this.Add(kvp);
    }
}  

ar putea fi îmbunătățit cu ușurință prin utilizarea AddRange() din List<T> astfel

public DuplicateDictionary(List<KeyValuePair<TKey, TValue>> list)
{
    this.AddRange(list);
}

dar acest lucru nu este cu adevărat necesar în acest mod, deoarece aveți, de asemenea, un ctor care ia un element Dictionary<TKey, TValue> ca parametru. Vă sugerez să înlocuiți ambii ctors cu unul diferit care să ia doar an IEnumerable<KeyValuePair<TKey, TValue>> ca de exemplu

public DuplicateDictionary(IEnumerable<KeyValuePair<TKey, TValue>> items)
{
    this.AddRange(items);
}  

care poate fi apelat folosind un Dictionary și a List.

Acest lucru arată bine, dar încă putem face mai bine folosind ctor-ul de la List în schimb, astfel

public DuplicateDictionary(IEnumerable<KeyValuePair<TKey, TValue>> items)
    : base(items)
{  } 

Comentarii

  • Ce face baza? Scuzați-mi ignoranța.  > Por hexagonest.
  • Aceasta este apelarea ctor al clasei moștenite.  > Por Heslacher.
Razor

Ar putea fi de ajutor dacă ați explica mai întâi problema pe care încercați să o rezolvați, dar voi încerca și eu.

Nu cred că această clasă ar trebui să aibă un motiv pentru a exista. O cheie este doar atât, o cheie. Dacă aveți chei duplicate și valori duplicate, ceea ce căutați în esență este o grupare sau un dicționar cu un set sau o listă ca valoare.

Ceea ce aveți este o listă de KeyValuePairs care nu este același lucru cu un Dictionary 🙂

Dicționarele beneficiază de faptul că au chei unice prin faptul că vă oferă căutări rapide, nu sunt sigur ce beneficii obțineți dacă aveți un DuplicateDictionary.

t3chb0t

Cred că doriți să aveți un fel de dicționar cu cheie unică cu mai multe valori. Așadar, vă sugerez să folosiți, de exemplu, un List<> pentru a păstra valorile.

Iată un exemplu:

public class DuplicateDictionary<TKey, TValue> : Dictionary<TKey, List<TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>
{
    public new IEnumerable<KeyValuePair<TKey, TValue>> this[TKey key]
    {
        get
        {
            List<TValue> values;
            if (!TryGetValue(key, out values))
            {
                return Enumerable.Empty<KeyValuePair<TKey, TValue>>();
            }

            return values.Select(v => new KeyValuePair<TKey, TValue>(key, v));
        }
        set
        {
            foreach (var _value in value.Select(kvp => kvp.Value))
            {
                Add(key, _value);
            }
        }
    }



    public void Add(TKey key, TValue value)
    {
        List<TValue> values;
        if (!TryGetValue(key, out values))
        {
            values = new List<TValue>();
            Add(key, values);
        }
        values.Add(value);
    }

    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        foreach (var item in ((Dictionary<TKey, List<TValue>>)this))
        {
            foreach (var value in item.Value)
            {
                yield return new KeyValuePair<TKey, TValue>(item.Key, value);
            }
        }
    }
}

static void Main(string[] args)
{
    var dupDic = new DuplicateDictionary<string, string>();

    dupDic.Add("abc", "123");
    dupDic.Add("abc", "456");
    dupDic.Add("xyz", "789");
    dupDic.Add("xyz", "098");
    dupDic.Add("xyz", "290");

    foreach (var kvp in dupDic)
    {
        Console.WriteLine("Key = 
{0}
 Value = 
{1}
", kvp.Key, kvp.Value);
    }

    Console.ReadKey();
}

Nagesh Hugar

Puteți utiliza List of KeyValuePair pentru a stoca duplicatele

Exemplu :

List<KeyValuePair<string, string>> listKeyValPair= new List<KeyValuePair<string, string>>();

KeyValuePair<string, string> keyValue= new KeyValuePair<string, string>("KEY1", "VALUE1");

listKeyValPair.Add(keyValue);

Comentarii

  • Bine ați venit la Code Review! Vă rugăm să citiți Cum să scriu un răspuns bun: „Fiecare răspuns trebuie să conțină cel puțin un observație pertinentă despre codul din întrebare.” Vă rugăm să explicați de ce sugestia dvs. ar reprezenta o îmbunătățire.-  > Por Sᴀᴍᴍ Onᴇᴌᴀᴀ.