2017-02-21 2 views
0

У меня есть требование, когда я хотел бы использовать словарь для хранения пар «ключ = значение», однако теперь мне нужно хранить «повторяющиеся» значения ключей.Изменение дубликата Значение ключа при вводе в словарь (C#)

У меня есть строка с разделителями текста (с разделителями с характером трубы («|»), который я раскололась в массив, а затем в словаре (см ниже)

string[] t = rawMessage.Split(new[] { '|', '|' }, StringSplitOptions.RemoveEmptyEntries); 
      message = t.ToDictionary(s => s.Split('=')[0], s => s.Split('=')[1]); 

Это прекрасно работает, если нет дубликаты существуют, но я хочу, чтобы хранить дубликаты ключей в пути, который регулирует значение ключа перед вставкой.

примера

A=1|B=2|C=3|D=4|D=5|D=5 

Я хочу, чтобы ключевое значение быть отрегулировано на что-то Лик e:

A=1 
B=2 
C=3 
D=4 
D[1]=5 
D[2]=5 

Таким образом, я могу вытащить запись 2-й и 3-й «D» записей, так как они имеют новое значение ключа.

Каждый дубликат является уникальной записью, поэтому я хотел бы иметь возможность ссылаться тогда в том порядке, в котором они были введены. четвертая запись будет, например, D [4]. Предложение об использовании одного и того же ключевого значения для всех значений может/будет запутывающим, и я могу в конечном итоге вытащить неправильную информацию (но помните об этом).

Я хотел бы избежать необходимости заранее прокручивать массив, и задался вопросом, знает ли кто-нибудь, как я могу выполнить это на части ToDictionary вышеприведенного кода.

Извинения за довольно простое объяснение. Многие из тем касаются удаления дубликатов в словарях, и я понимаю, что это не подразумевается использование словаря.

+0

Вы должны разработать собственную структуру данных, чтобы следить за дубликатами. Или сделайте то, что сказал @ itsme86. Но это зависит от того, как вы хотите получить эту информацию. –

+0

Как потребители вашего словаря знают, хотят ли они первый ключ «D» или второй? – Quantic

+0

Quantic - первая запись будет D, вторая D [1], третья D [2] и так далее. Формат «[]» - это просто уникальная вставка ключа. Затем они будут вводить ключ, который они хотели бы видеть. – Arclight

ответ

5

Если вы хотите связать несколько значений с помощью ключа, вы можете просто сделать значение части пары списка:

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

char key = 'D'; 
int value = 5; 

if (!dict.ContainsKey(key)) 
    dict[key] = new List<int>(); 
dict[key].Add(value); 
+0

Это звучит как хорошее решение. Сделал это раньше. Много раз. –

+0

Спасибо за комментарий. Проблема заключается в том, что каждый дублирующий ключ представляет собой отдельную запись, поэтому объединение их вместе означает, что я потеряю возможность вытащить данные на основе значения unqiue. Я уточню вопрос немного подробнее. – Arclight

+2

@Arclight Я не уверен, что я следую. Вы можете просто выполнить 'dict ['D'] [1]', чтобы получить запись 2-го D. – itsme86

2

Вы можете использовать словарь с коллекционной ценностью на основе:

Dictionary<string, List<int>> 

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

Или вы можете использовать Lookup<TKey, TElement> класс, но это не дает индексации массива на элементы стоимости:

Lookup<string, int> 

который поддерживает группировку под ключ (так Перечислимый из TElement). Документы для него: here.


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

+0

@Fabio достаточно справедливо. Я оставлю это для вашего комментария, чтобы добавить - OP действительно не говорит об использовании, отличном от возможности индексировать в том порядке, в котором они были вставлены, что «Lookup» на самом деле не обеспечивает ни одного способа, но я чувствую, что это проблема XY. –

3

Вы можете использовать GroupBy к группе результирующего набора с помощью ключа, то сглаживать группировки, используя SelectMany, проецирования нужного ключа, используя метод перегрузку Select с параметром индекса:

var message = t 
    .Select(s => s.Split('=')) 
    .GroupBy(s => s[0], s => s[1]) 
    .SelectMany(g => g.Select((v, i) => new 
    { 
     Key = i == 0 ? g.Key : g.Key + "[" + i + "]", 
     Value = v 
    })) 
    .ToDictionary(e => e.Key, e => e.Value); 
0

Well..I'm собирается к базовому ответу, без использования LINQ. Что я хотел бы сделать, это сделать свой собственный ToDictionary метод, просто проверить, если ключ существует, и если это произойдет, создать новый ключ и добавить его в Dictionary, что-то вроде этого:

public Dictionary<string,string> ToDictionary(string[] t) 
{ 
    Dictionary<string, string> dict = new Dictionary<string, string>(); 
    foreach (string s in t) 
    { 
     string[] reg = s.Split('='); 
     int i = 1; 
     while (dict.ContainsKey(reg[0])) 
     { 
      if (!reg[0].Contains('[')) 
       reg[0] = reg[0] + "[" + i.ToString() + "]"; 
      else 
       reg[0] = reg[0].Replace((i - 1).ToString(), i.ToString()); 
      i++; 
     } 

     dict.Add(reg[0], reg[1]); 
    } 
    return dict; 
} 

Это легко может быть преобразован в метод расширения.

0

Как Адам Халдсворт сказал, что вы можете использовать Lookup.

Вот фрагмент, основанный на ответе Адама Халдсворта.

var str = @"A=1|B=2|C=3|D=4|D=5|D=5"; 
string[] t = str.Split(new[] { '|', '|' }, StringSplitOptions.RemoveEmptyEntries); 
var message = t.ToLookup(s => s.Split('=')[0], s => Convert.ToInt32(s.Split('=')[1])); 
var res = message.ToDictionary(i=>i.Key, x=>x.LastOrDefault()); 

Edit:

После прочтения вашего вопроса снова я понимаю, что вы хотите, D = 4 значения также.

var res = message.SelectMany(i => i.Select((x, y) => new 
{ 
    Key = i.Key, 
    Value = x 
})).GroupBy(q=>q.Value) 
    .SelectMany(x=>x.ToLookup(xx=>xx.Key, xx=>xx.Value)); 
0

Альтернативный способ заключается в использовании NameValueCollection в System.Collections.Specialized. Интересная вещь с NameValueCollection заключается в том, что если есть повторяющиеся значения для одного и того же ключа, она будет сохранять значения в том же ключе, что и значение, разделенное запятой. Ключ будет таким же, но значения, которые вы, возможно, должны отделить. Ниже приведен быстрый образец и вывод.

class Program 
{ 
    static void Main(string[] args) 
    { 
     NameValueCollection col = new NameValueCollection(); 
     col.Add("A", "1"); 
     col.Add("A", "2"); 
     col.Add("B", "0"); 
     col.Add("B", "1"); 
     col.Add("B", "3"); 
     col.Add("D", "1"); 
     foreach (string key in col.AllKeys) 
     { 
      Console.WriteLine(key + " " + col[key] + "\n"); 
     } 
     Console.ReadKey(); 
    } 
} 

Выход 1,2 B 0,1,2 D 1 Output

Смежные вопросы