Хеш-таблица с несколькими значениями для одного ключа

Я хочу хранить несколько значений в одном ключе, например:

HashTable obj = new HashTable();
obj.Add("1", "test");
obj.Add("1", "Test1");

Прямо сейчас это вызывает ошибку.


person user557168    schedule 29.12.2010    source источник
comment
Если ключи являются числами, используйте int в качестве ключа, а не string, если применимо.   -  person abatishchev    schedule 29.12.2010
comment
Этот вопрос дублирует stackoverflow.com/questions/2478567 и stackoverflow.com/questions/4454075   -  person Eric Lippert    schedule 29.12.2010


Ответы (11)


вы можете поместить свой test,test1,test2,... в таблицу, а затем поместить эту таблицу в Hashtable как значение ключа, которое будет одинаковым для всех.

Например, попробуйте что-то вроде этого:

List<string> list = new List<string>();
list.Add("test");
list.Add("test1"); 

а потом:

HashTable obj = new HashTable();
obj.Add("1", list);
person Grace    schedule 29.12.2010

Вы не можете использовать тот же ключ в Dictionary / Hashtable. Я думаю, вы хотите использовать список для каждого ключа, например (VB.NET):

Dim dic As New Dictionary(Of String, List(Of String))
Dim myValues As New List(Of String)
myValues.Add("test")
myValues.Add("Test1")
dic.Add("1", myValues)

C#:

Dictionary<string, List<string>> dic = new Dictionary<string, List<string>>();
List<string> myValues = new List<string>();
myValues.Add("test");
myValues.Add("Test1");
dic.Add("1", myValues);
person Tim Schmelter    schedule 29.12.2010

Я использую свой собственный MultiDictionary класс. Он основан на Dictionary<TKey,List<TValue>>, но предлагает немного синтаксического сахара поверх этого. Должно быть легко реализовать Entry<TValue> IList<T>

public class MultiDictionary<TKey, TValue>
{
    private Dictionary<TKey, List<TValue>> data = new Dictionary<TKey, List<TValue>>();

    public struct Entry : IEnumerable<TValue>
    {
        private readonly MultiDictionary<TKey, TValue> mDictionary;
        private readonly TKey mKey;

        public TKey Key { get { return mKey; } }

        public bool IsEmpty
        {
            get
            {
                return !mDictionary.data.ContainsKey(Key);
            }
        }

        public void Add(TValue value)
        {
            List<TValue> list;
            if (!mDictionary.data.TryGetValue(Key, out list))
                list = new List<TValue>();
            list.Add(value);
            mDictionary.data[Key] = list;
        }

        public bool Remove(TValue value)
        {
            List<TValue> list;
            if (!mDictionary.data.TryGetValue(Key, out list))
                return false;
            bool result = list.Remove(value);
            if (list.Count == 0)
                mDictionary.data.Remove(Key);
            return result;
        }

        public void Clear()
        {
            mDictionary.data.Remove(Key);
        }

        internal Entry(MultiDictionary<TKey, TValue> dictionary, TKey key)
        {
            mDictionary = dictionary;
            mKey = key;
        }

        public IEnumerator<TValue> GetEnumerator()
        {
            List<TValue> list;
            if (!mDictionary.data.TryGetValue(Key, out list))
                return Enumerable.Empty<TValue>().GetEnumerator();
            else
                return list.GetEnumerator();
        }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

    public Entry this[TKey key]
    {
        get
        {
            return new Entry(this, key);
        }
    }
}
person CodesInChaos    schedule 29.12.2010

Вы можете использовать словарь.

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

Образец кода:

class MappedValue
{
    public string SomeString { get; set; }
    public bool SomeBool { get; set; }
}

Dictionary<string, MappedValue> myList = new Dictionary<string, MappedValue>;
person Leniel Maccaferri    schedule 29.12.2010
comment
Если OP может использовать .NET 4.0, он также может использовать только Tuble<string, bool> и т. Д. - person abatishchev; 29.12.2010

Это вызывает ошибку, потому что вы добавляете один и тот же ключ дважды. Попробуйте использовать Dictionary вместо HashTable.

Dictionary<int, IList<string>> values = new Dictionary<int, IList<string>>();
IList<string> list = new List<string>()
{
    "test", "Test1"
};
values.Add(1, list);
person hunter    schedule 29.12.2010
comment
IList предназначен для динамического хранения + получения по индексу. Ведь просто динамическое хранение - это `ICollection ‹string›, не так ли? - person abatishchev; 29.12.2010
comment
Конечно, в зависимости от того, что он хочет, он может использовать IEnumerable, ICollection, IList, _4 _... все, что ему нужно - person hunter; 29.12.2010

Наверное, через 4 года, но надеюсь, кому-то потом это поможет. Как упоминалось ранее в сообщении, невозможно использовать один и тот же ключ для разных значений в Hashtable (ключ, значение). Тем не менее, вы можете создать список или некоторый объект как значение в паре ключ / значение HashTable.

//instantiate new Hashtable
Hashtable hashtable = new Hashtable();

//create a class that would represent a value in the HashTable
public class SomeObject
{
    public string value1 { get; set;}
    public string value2 { get; set;}
}

//create a List that would store our objects
List<SomeObject> list = new List<someObject>();

//add new items to the created list
list.Add(new SomeObject() 
             { 
                 value1 = "test", 
                 value2 = "test1"
             });
list.Add(new SomeObject() 
             {
                 value1 = "secondObject_value1" 
                 value2 = "secondObject_value2"
             })

//add key/value pairs to the Hashtable.
hashTable.Add("1", list[0]);
hashTable.Add("2", list[1]);

Затем, чтобы получить эти данные:

//retrieve the value for the key "1"
SomeObject firstObj = (SomeObject)hashTable[1];
//retrieve the value for the key "2"
SomeObject secondObj = (SomeObject)hashTable[2];
Console.WriteLine("Values of the first object are: {0} and {1}", 
                                             firstObj.value1,firstObj.value2);
Console.WriteLine("Values of the second object are {0} and {1}",
                                             secondObj.value1, secondObj.value2);
// output for the WriteLine:
Values of the first object are: test and test1
Values of the second object are secondObject_value1 and secondObject_value2
person Shukhrat Raimov    schedule 08.08.2014

Сохраните список в хеш-таблице:

obj.Add("1",new List<string>());
(obj["1"] as List<string>).Add("test");
(obj["1"] as List<string>).Add("test1");

Это обычная уловка.

person Aliostad    schedule 29.12.2010
comment
Если вы уверены в результирующем типе, используйте cast, а не оператор as. И в любом случае - используйте универсальную коллекцию, а не неуниверсальную коллекцию .NET 1.x. - person abatishchev; 29.12.2010

JFYI, вы можете объявить свой dic следующим образом:

Dictionary<int, IList<string>> dic = new
{
    { 1, new List<string> { "Test1", "test1" },
    { 2, new List<string> { "Test2", "test2" }
};
person abatishchev    schedule 29.12.2010

Вы ищете Lookup, который может изначально хранить несколько значений для каждый ключ.

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

public class LookupEntry
{
    public string Key { get; set; }
    public string Value { get; set; }
}

var list = new List<LookupEntry>(new LookupEntry [] 
                                    {
                                    new LookupEntry() {Key="1", Value="Car" }, 
                                    new LookupEntry() {Key="1", Value="Truck"},
                                    new LookupEntry() {Key="2", Value="Duck"}
                                    });


var lookup = list.ToLookup(x => x.Key, x => x.Value);
var all1s = lookup["1"].ToList();
person BrokenGlass    schedule 29.12.2010
comment
Lookup неизменен. Это может быть хорошо, но может не сработать в сценарии OP. - person CodesInChaos; 29.12.2010

Вы можете использовать NameValueCollection - работает так же, как хеш-таблица, и имеет «GetValues ​​()».

person Andy Mazanec    schedule 13.06.2013

Было бы лучше использовать две хэш-таблицы, как я использовал в этой библиотеке

person r.mirzojonov    schedule 20.09.2013