C #: словарь, проиндексированный списком - PullRequest
1 голос
/ 10 ноября 2011

Я пытаюсь написать программу, в которой словарь индексируется списком.(Поверьте мне, я делаю, и да, есть вариант, но мне нравится индексирование по списку).Есть минимальный работающий (на самом деле не работающий, только одна последняя строка, которая является проблемой):

using System;
using System.Collections.Generic;

namespace test
{
    class Program
    {
    static void Main(string[] args)
    {
        Dictionary<List<String>, int> h = new Dictionary<List<string>,int>();

        List<String> w = new List<string> {"a"};
        h.Add(w, 1);

        w = new List<string>{"b"};
        h.Add(w,2);

        w = new List<string>{"a"};

        int value = 0;
        h.TryGetValue(w, out value);
        Console.WriteLine(value+" "+h[w]);
    }
}

, если кто-то отладит эту программу, он ясно увидит, что в h есть два элемента, но все же этиэлементы не доступны через правильные индексы --- h [w].Я не прав или происходит что-то странное?

Ответы [ 4 ]

7 голосов
/ 10 ноября 2011

Проблема с вашим приложением связана с тем, что:

new List<String> { "a" } != new List<String> { "a" }

Равенство для списков проверяет, относятся ли две ссылки к одному и тому же экземпляру. В этом случае они не делают. Вместо этого вы создали два списка с одинаковыми элементами ... которые не делают их равными.

Вы можете решить проблему, создав собственный Equal Comparer:

public class ListEqualityComparer<T> : IEqualityComparer<List<T>>
{
    public bool Equals(List<T> list1, List<T> list2)
    {
        return list1.SequenceEquals(list2);
    }

    public int GetHashCode(List<T> list)
    {
        if(list != null && list.Length > 0)
        {
            var hashcode = list[0].GetHashCode();
            for(var i = 1; i <= list.Length; i++)
                hashcode ^= list[i].GetHashCode();

            return hashcode;
        }

        return 0;
    }
}

А затем передать это конструктору Dictionary:

Dictionary<List<String>, int> h = 
    new Dictionary<List<string>,int>(new ListEqualityComparer<String>());
2 голосов
/ 10 ноября 2011

Проблема заключается в индексировании по списку, по которому вы индексируете не данные в списке, но вы, по сути, индексируете указатель памяти на список (т. Е. Адрес памяти, где расположен этот список).

Вы создали один список в одной ячейке памяти, затем вы создали совершенно другой список в другой ячейке памяти (т.е. при создании нового экземпляра).Два списка отличаются, даже если они содержат одни и те же данные, и это означает, что вы можете добавить столько слов, сколько хотите в словарь.

Одно из решений - вместо индексации по списку будет индексировать по строке и использоватьСписок через запятую, содержащий все данные в вашем списке в виде индекса.

1 голос
/ 10 ноября 2011

Класс Dictionary использует сравнение ссылок для поиска указанного ключа, поэтому даже если списки содержат одинаковые элементы, они различаются.

1 голос
/ 10 ноября 2011

Это никогда не сработает, потому что методы List<T> Equals и GetHashCode не учитывают содержимое списка. Если вы хотите использовать коллекцию объектов в качестве ключа, вам необходимо реализовать собственный тип коллекции, который переопределяет Equals таким образом, чтобы проверять равенство объектов в коллекции (возможно, используя Enumerable.SequenceEqual.)

...