2014-12-15 2 views
30

У меня есть метод, который возвращает группы технических специалистов, которые работали на некоторых проектах, например:Что является альтернативой словарям на C#, что позволяет дублировать ключи?

project 1 | John 
project 1 | Tim 
project 2 | John 
project 2 | Dave 

Первоначально я пытался создать словарь, который, как правило, мой идти к коллекции пар ключ-значение, но в этом случае я не могу использовать его, потому что у меня не может быть дублирующего ключа (проекта). Какую альтернативу я могу использовать?

Моя единственная мысль - создать Dictionary<Project, List<Technicians>>, но есть ли что-то намного проще?

+1

словарь гарантирует, что вы не будете иметь дубликаты ключей в нем, в чем проблема? –

+0

@VsevolodGoloviznin проблема в том, что я хочу иметь дубликат ключа, но по-прежнему имеют уникальные пары ключевых значений (если я могу ограничить эту часть). – AdamMc331

+15

'Словарь <Проект, список >' выглядит достаточно хорошо. Но если вам действительно не нужен ключ «Project» (т. Е. Вам не нужно получать всех техников какого-либо проекта), вы можете попробовать «Список >' –

ответ

44

В вашем случае эта же клавиша связана с несколькими значениями, поэтому стандартный словарь не подходит, как есть. Вы можете объявить его как Dictionary<Key, List<Values>>.

Но, кроме того, вы можете использовать:

Lookup класс, который

Представляет коллекцию ключей каждый отображенных на один или несколько значений.

Для этого вам нужна рамка 3.5 и более.

+0

У 'Lookup' есть открытый конструктор? – Groo

+0

@Groo: нет, но легко преобразовать последовательность или словарь с расширением 'ToLookup'. – Dennis

+0

Я думаю, что класс Lookup замалчивает реальную проблему здесь. OP имеет отношение между классами, которые должны быть смоделированы по свойству класса 'Project'. –

13

Что вам нужно, это отношения между Project и одного или нескольких техниках:

public class Project 
{ 
    public ICollection<Technician> Technicians { get; set; } 
} 

var project = new Project(); 
project.Technicians = new List<Technician>() 
{ 
    new Technician(), 
    new Technician() 
}; 

Ваши объекты должны отражать отношения в реальной жизни.

В качестве примечания, Вам может быть интересно узнать о Domain-driven design.

public void LoadTechnicians(Project project) 
{ 
    List<Technician> techs = new List<Technician>(); 

    // query the database and map Technician objects 

    // Set the "Technicians" property 
    project.Technicians = techs; 
} 
+0

Как насчет ** быстро ** Поиск технических специалистов по проекту? – Dennis

+0

Это уже связано с тем, что в «Проекте» есть список техников. –

+1

@ Dennis Если у вас есть «Проект», и для этого вам нужны все «Техники», то в этом примере все, что вам нужно сделать, это вызвать свойство «Проект», а не загружать его в словарь и обрабатывать вывод. Это будет легче и быстрее. – Servy

4

Я не думаю, что с вашим решением что-то не так. В конце концов, вы можете легко получить доступ ко всем членам команды по проекту. Но в качестве альтернативы вы можете попробовать List<KeyValuePair<Project, Technician>>. Вы поддерживаете отношение ключ-значение, но без ограничений не повторяющихся ключей. Это гораздо проще, чем у вас сейчас? Зависит от вариантов использования.

Кроме того, вы можете скрыть эту структуру за своей реализацией пользовательской коллекции.

+0

Кажется, они не хотят «проект 1 | Джон "дважды. Может быть, 'HashSet >'? –

+0

@ ArturoTorresSánchez Нет, я не хочу повторять пары Key-Value. В проекте 1 не могут быть повторены технические специалисты. – AdamMc331

+0

@ McAdam331, ... Я собирался сказать, что 'KeyValuePair' переопределяет' Equals', но, похоже, на самом деле это не так. Думаю, что 'Tuple' может быть лучшим вариантом (все еще с' HashSet'). –

12

an experimental NuGet package from MS that contains MultiValueDictionary.

В принципе, это как Dictionary<Project, List<Technicians>>, за исключением того, что вам не нужно повторять всю логику для управления List s при каждом доступе к ней.

+2

Просто заметьте, но это уже не MultiDictionary. Он был переименован в MultiValueDictionary для лучшего разъяснения того, что он делает: http://blogs.msdn.com/b/dotnet/archive/2014/08/05/multidictionary-becomes-multivaluedictionary.aspx – Greg

0

Я скопировал свой собственный ответ от this post.

Достаточно просто «свернуть свою» версию словаря, которая позволяет вводить записи «дублировать ключ». Вот грубая простая реализация. Возможно, вы захотите рассмотреть возможность добавления поддержки в большинстве случаев (если не все) на IDictionary<T>.

public class MultiMap<TKey,TValue> 
{ 
    private readonly Dictionary<TKey,IList<TValue>> storage; 

    public MultiMap() 
    { 
     storage = new Dictionary<TKey,IList<TValue>>(); 
    } 

    public void Add(TKey key, TValue value) 
    { 
     if (!storage.ContainsKey(key)) storage.Add(key, new List<TValue>()); 
     storage[key].Add(value); 
    } 

    public IEnumerable<TKey> Keys 
    { 
     get { return storage.Keys; } 
    } 

    public bool ContainsKey(TKey key) 
    { 
     return storage.ContainsKey(key); 
    } 

    public IList<TValue> this[TKey key] 
    { 
     get 
     { 
      if (!storage.ContainsKey(key)) 
       throw new KeyNotFoundException(
        string.Format(
         "The given key {0} was not found in the collection.", key)); 
      return storage[key]; 
     } 
    } 
} 

Быстрый пример того, как использовать его:

const string key = "supported_encodings"; 
var map = new MultiMap<string,Encoding>(); 
map.Add(key, Encoding.ASCII); 
map.Add(key, Encoding.UTF8); 
map.Add(key, Encoding.Unicode); 

foreach (var existingKey in map.Keys) 
{ 
    var values = map[existingKey]; 
    Console.WriteLine(string.Join(",", values)); 
} 
Смежные вопросы