Багатозначний словник


76

Як створити багатозначний словник на c #?

Наприклад, Dictionary<T,T,T>де перший T - ключ, а інші два - значення.

так це було б можливо: Dictionary<int,object,double>

Дякую

Відповіді:


62

Просто створіть Pair<TFirst, TSecond>тип і використовуйте його як своє значення.

У мене є приклад одного в моєму C # у вихідному коді Depth . Тут відтворено для простоти:

using System;
using System.Collections.Generic;

public sealed class Pair<TFirst, TSecond>
    : IEquatable<Pair<TFirst, TSecond>>
{
    private readonly TFirst first;
    private readonly TSecond second;

    public Pair(TFirst first, TSecond second)
    {
        this.first = first;
        this.second = second;
    }

    public TFirst First
    {
        get { return first; }
    }

    public TSecond Second
    {
        get { return second; }
    }

    public bool Equals(Pair<TFirst, TSecond> other)
    {
        if (other == null)
        {
            return false;
        }
        return EqualityComparer<TFirst>.Default.Equals(this.First, other.First) &&
               EqualityComparer<TSecond>.Default.Equals(this.Second, other.Second);
    }

    public override bool Equals(object o)
    {
        return Equals(o as Pair<TFirst, TSecond>);
    }

    public override int GetHashCode()
    {
        return EqualityComparer<TFirst>.Default.GetHashCode(first) * 37 +
               EqualityComparer<TSecond>.Default.GetHashCode(second);
    }
}

2
Яка перевага перед звичайним KeyValuePair? Чи є якісь накладні витрати при використанні KeyValuePair?
tanascius

1
В основному це різниця в акцентах - хоча KeyValuePair дійсно інкапсулює пару значень, це передбачає певний тип взаємозв'язку між ними ... цього не потрібно.
Джон Скіт,

19
Це те саме, що Tuple в .Net 4.0?
adam0101

2
@ adam0101: Так само, так.
Джон Скіт,

4
@BasselAlkhateeb: Якщо вам не подобається можливість повертати значення, тоді так, це добре ...
Джон Скіт,

64

Якщо ви намагаєтесь згрупувати значення разом, це може бути чудовою можливістю створити просту структуру або клас і використовувати це як значення у словнику.

public struct MyValue
{
    public object Value1;
    public double Value2;
}

тоді ви могли б отримати свій словник

var dict = new Dictionary<int, MyValue>();

Ви можете навіть піти на крок далі і впровадити власний клас словника, який буде обробляти будь-які спеціальні операції, які вам знадобляться. наприклад, якщо ви хочете мати метод Add, який приймає int, object та double

public class MyDictionary : Dictionary<int, MyValue>
{
    public void Add(int key, object value1, double value2)
    {
        MyValue val;
        val.Value1 = value1;
        val.Value2 = value2;
        this.Add(key, val);
    }
}

тоді ви можете просто створити екземпляр та додати до словника таким чином, і вам не доведеться турбуватися про створення структур "MyValue":

var dict = new MyDictionary();
dict.Add(1, new Object(), 2.22);

30
Dictionary<T1, Tuple<T2, T3>>

Редагувати: Вибачте - я забув, що ви не отримуєте Tuples, поки не вийде .NET 4.0. Ой!


1
Кортежі знаходяться в .NET 4.0 BCL, і це не пов'язано з C # 4.0. Функції C # 4.0 не згадують про підтримку кортежу. Будь ласка, виправте свою відповідь.
Eriawan Kusumawardhono

Проблема кортежу полягає в тому, що значення не називаються.
ProfK

2
Крім того, значення кортежу читаються лише для читання, що може бути нормальним для деяких випадків, але їх слід враховувати перед їх використанням.
Себастьян Верк

Дуже хороша інформація. Дозволив мені розширити існуючий словниковий код. Дякую.
Mike Malter

6

Я думаю, що це цілком надмірно для семантики словника, оскільки словник за визначенням - це сукупність ключів та відповідних значень, як і те, як ми бачимо книгу словника мови, яка містить слово як ключ та його описове значення як значення.

Але ви можете представити словник, який може містити набір значень, наприклад:

Dictionary<String,List<Customer>>

Або словник ключа та значення як словник:

Dictionary<Customer,Dictionary<Order,OrderDetail>>

Тоді у вас буде словник, який може мати кілька значень.


1
Як тільки ви починаєте вкладати словники, ваш код починає виглядати як багатовимірні масиви.
IAbstract

@IAbstract це не так схоже в семантиці. Багатовимірні масиви не дбають про комбінацію ключів-значень. Також багатовимірні масиви не дбають про максимум двох елементів (як словник повинен мати).
Eriawan Kusumawardhono

@eriawan: Я не думаю, що мені було зрозуміло :) ... припустимо значення int для ключів: myColl[0][1]... виглядає як багатовимірний масив. Коли ви починаєте вкладати колекції, я вважаю, що пора належним чином інкапсулювати колекцію 'value'.
IA Abstract

@IAbstract це хороший момент! Тепер я розумію вашу думку у вашому останньому коментарі. Я згоден, що нам слід правильно інкапсулювати колекцію значень.
Eriawan Kusumawardhono

5

Я не думаю, що ви можете зробити це безпосередньо. Можна було б створити клас , який містить як ваш objectі doubleі покласти його екземпляр в словнику , хоча.

class Pair
{
    object obj;
    double dbl;
}

Dictionary<int, Pair> = new Dictionary<int, Pair>();

2

Якщо значення пов’язані, чому б не інкапсулювати їх у клас і просто використовувати звичайний старий словник?


Також буде читабельнішим, ніж Pair і Tuple. Що таке перший, другий, пункт1, пункт2?
KornMuffin

1

Ви описуєте мультимапу.

Ви можете зробити значення об'єктом List, щоб зберегти більше одного значення (> 2 для розширюваності).

Замінити об’єкт словника.


1

Я вирішив за допомогою:

Dictionary<short, string[]>

Подобається це

Dictionary<short, string[]> result = new Dictionary<short, string[]>();
result.Add(1,
           new string[] 
                    { 
                    "FirstString",
                    "Second"
                    }
                );
        }
return result;

1

Я знаю, що це стара тема, але - оскільки про це не згадували, це працює

  Dictionary<string, object> LookUp = new Dictionary<string, object>();
  LookUp.Add("bob", new { age = "23", height = "2.1m", weight = "110kg"});
  LookUp.Add("jasper", new { age = "33", height = "1.75m", weight = "90kg"});
  foreach(KeyValuePair<string, object> entry in LookUp )
  {
      object person = entry.Value;
      Console.WriteLine("Person name:" + entry.Key + " Age: "  + person.age);          
  }

0

Ось реалізація одного ключа для багатозначної карти в C #, який використовує набір типів ключів:

https://github.com/ColmBhandal/CsharpExtras/blob/master/CsharpExtras/Dictionary/MultiValueMapImpl.cs

Словник поводиться як звичайний словник із типу ключа на набір типу значення, але також забезпечує функціональність безпосереднього додавання одного значення типу значення, а у фоновому режимі обробляє створення базового набору та / або доповнення до цей набір.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.