Hashtable / Dictionary, но с ключом, состоящим из нескольких значений? - PullRequest
3 голосов
/ 03 марта 2010

Допустим, у меня есть объект, у которого есть stringProp1, stringProp2. Я хочу хранить каждую комбинацию stringProp1, stringProp2 в словаре. Первоначально я сохранял ключ как key = stringProp1 + stringProp2, но это может фактически вызвать ошибку в зависимости от 2 значений. Является ли лучшим решением этой проблемы создание пользовательского словарного класса или есть лучший способ использования встроенных классов .NET?

Ответы [ 6 ]

3 голосов
/ 03 марта 2010

В .NET 4 вы можете использовать System.Tuple в качестве ключа.

var dict = new Dictionary<Tuple<string,string>, int>();
dict.Add(Tuple.Create("foo","bar"), 1);
1 голос
/ 05 марта 2010

В зависимости от того, как вы заполняете словарь и что вы делаете с ним, в качестве ключа можно использовать анонимный тип. Например, если у вас есть класс Person:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
}

И если у вас была последовательность из них, IEnumerable<Person>, и вы хотели создать словарь, который сопоставляет имена с возрастами, вы можете написать:

var personDictionary = people.ToDictionary(p => new { p.FirstName, p.LastName });

Это дает вам словарь с именем и фамилией в качестве ключа и сохраняет весь Person в качестве значения. Позже вы можете найти ключ с помощью:

personDictionary.TryGetValue(new { FirstName = "John", LastName = "Smith" },
    out person);

Это не поможет вам, если вы пытаетесь передать словарь между различными классами или даже методами, им становится трудно управлять, но для быстрой обработки данных в одном методе он прекрасно работает. Фактически, довольно часто используют анонимные классы в качестве ключа для метода расширения GroupBy или синтаксиса понимания запросов group by.

1 голос
/ 05 марта 2010

Неважно, какую структуру данных вы используете в качестве ключа, если ключ содержит необходимую информацию для компаратора для правильного сравнения / хеширования.

Вы даже можете использовать свои объекты в качестве ключей в словареи сравните по любому полю с подходящей EqualityComparer реализацией.Этот сравнивает два строковых свойства, используя порядковое сравнение:

class MyObject
{
    public string StringProp1 { get; set; }
    public string StringProp2 { get; set; }
    public MyObject(string prop1, string prop2)
    {
        StringProp1 = prop1;
        StringProp2 = prop2;
    }
}

class MyObjectComparerS1S2 : EqualityComparer<MyObject>
{
    //Change this if you need e.g. case insensitivity or 
    //culture-specific comparisons
    static StringComparer comparer = StringComparer.Ordinal;

    public override bool Equals(MyObject x, MyObject y)
    {
        return 
            comparer.Equals(x.StringProp1, y.StringProp1) &&
            comparer.Equals(x.StringProp2, y.StringProp2);
    }

    public override int GetHashCode(MyObject obj)
    {
        //Uncomment this if running in a checked context
        //Copycat of Jon Skeet's string hash combining
        //unchecked
        //{
            return 
                (527 + comparer.GetHashCode(obj.StringProp1)) * 31 +
                comparer.GetHashCode(obj.StringProp2);
        //}
    }

    public static readonly MyObjectComparerS1S2 Instance = 
        new MyObjectComparerS1S2();

}

static void Main(string[] args)
{
    Dictionary<MyObject, MyObject> dict = 
        new Dictionary<MyObject, MyObject>(MyObjectComparerS1S2.Instance);
    MyObject obj = new MyObject("apple", "plum");
    dict.Add(obj, obj);
    MyObject search = new MyObject("apple", "plum");
    MyObject result = dict[search];
    Console.WriteLine("{0}:{1}", result.StringProp1, result.StringProp2);
}

Вы можете искать объект, создавая фиктивное, заполнив строковые ключи и используя фиктивный в качестве ключа для поиска.Если вам не нравится эта идея или она неосуществима, просто сделайте, как сказал @ Vlad , и извлеките ключи из структуры или класса.В этом случае измените компаратор для получения из EqualityComparer<MyKeyStructOrClass>.

Обратите внимание, что я использовал метод Джона Скита для объединения строковых хэшей.Это может быть лучше, чем метод XOR, найденный в MSDN .Если вы чувствуете, что это неадекватно стали, не стесняйтесь обращаться со строками с помощью другой хэш-реализации - Се * , Ропот , Боба Дженкина , или что вы веритеВот отличная страница о хеш-функциях , которая также имеет некоторый код C #.

1 голос
/ 03 марта 2010

Почему бы просто не использовать структуру с 2 строками в качестве ключа? Это было бы самым простым.

0 голосов
/ 03 марта 2010

Вы можете использовать алгоритм MD5 для получения значения для каждой строки, а затем суммировать два значения. Результат - ключ.
.NET предоставляет класс MD5CryptoServiceProvider в пространстве имен System.Security.Cryptography. Этот класс содержит метод ComputeHash для вычисления значения хеш-функции.

0 голосов
/ 03 марта 2010

Вы можете поставить разделитель там, если есть символ, который не появится ни в одной строке.

например

stringProp1 + "|" + stringProp2

Если нет, я бы порекомендовал Dictionary<string, Dictionary<string, MyValueType>> как в

var dictionary = new Dictionary<string, Dictionary<string, MyValueType>>();
// .... Do stuff
if (!dictionary.ContainsKey(stringProp1))
    dictionary.Add(stringProp1, new Dictionary<string, MyValueType>());
dictionary[stringProp1][stringProp2] = myValue;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...