2013-02-14 4 views
2

У меня есть список, содержащийся в словаре, который содержит follwing значенияРасщепление значение строки внутри списка <>

value a 
value b 
value c 
value 1, value 2, value3 
value d 

конечный результат я хотел бы это

value a 
value b 
value c 
value 1 
value 2 
value 3 
value d 

проблема Перебор словарь и попытка изменить коллекцию не будут работать, поскольку я пытаюсь ее модифицировать во время ее циклирования

string[] ar; 
     foreach (var kvp in dict) 
     { 
      if (kvp.Key == "STAR-016") 
      { 
       foreach (var v in kvp.Value) 
       { 
        if (v.Contains(',')) 
        { 
         ar = v.Split(','); 
         foreach (var a in ar) 
         { 
          kvp.Value.Add(a); 
         } 
        } 
       } 
      } 
     } 

Как я могу получить желаемый результат?

+6

Чего _exactly_ вы пытаетесь достичь? Каков конечный результат? – Oded

+0

Вы пытались создать список анотетов и добавили каждый результат к этому? – futile

+0

Является ли значение «значение 1, значение 2, значение 3» строковым литералом? –

ответ

2

Если предположить, что это всего лишь пример, и вы на самом деле хотите, чтобы это не только ключевой STAR-016 но и для всех, где значение (которая представляет собой List<string>) содержит запятую:

Dictionary<string, List<String>> dict = new Dictionary<string, List<String>>(); 
dict.Add("STAR-016", new List<string>() { 
    "value a", "value b", "value c", "value 1, value 2, value 3", "value d" 
}); 

foreach (var kvp in dict) 
{ 
    for (int i = kvp.Value.Count - 1; i >= 0; i--) 
    { 
     string str = kvp.Value[i]; 
     if (str.Contains(',')) 
     { 
      var parts = str.Split(',').Select(p => p.Trim()); 
      kvp.Value.RemoveAt(i); 
      kvp.Value.InsertRange(i, parts); 
     } 
    } 
} 

Demo

Я зацикливаюсь от конца до начала, чтобы избежать осложнений, потому что InsertRange добавит новые строки, которые увеличивают Count.
Я использую RemoveAt, чтобы заменить строки запятыми новыми строками (по одной для каждой части, разделенной запятой), которые добавляются. Я использую InsertRange вместо AddRange, потому что вы хотите сохранить заказ.

Результат:

value a 
value b 
value c 
value 1 
value 2 
value 3 
value d 
+0

Не уверен, но похоже, что OP хочет удалить исходный CSV. – JDB

+0

@ Cyborgx37: Но он использует 'foreach (var a in ar) { kvp.Value.Add (a); } ', чтобы добавить детали в список. Обратите внимание, что я отредактировал свой ответ, чтобы показать, как заменить отдельный элемент разделенными элементами, что кажется желательным. –

+0

Да, я согласен - образец кода явно неправильный. Я основываю свой комментарий на желаемом выходе. – JDB

2

Вы можете цикл корыта List используя for вместо foreach и изменять элементы

for (int i = 0; i < kvp.Value.Count; i++) 
{ 
    if (kvp.Value[i].Contains(',')) 
     ... 
} 
+0

Я думаю, что проблема в цикле - это не цикл словаря, а цикл . – JDB

+0

OP хочет заменить одну строку в каждом списке, которая содержит запятые с разделенными строками. Поэтому впоследствии список может увеличиться, но исходный элемент должен быть удален. –

+0

@ Cyborgx37 Использование вместо foreach - это решение, то же самое для словаря и списка. – VladL

2

Попытка с помощью LINQ:

var list = new List<string>() 
{ 
    "value a", 
    "value b", 
    "value 1, value 2, value 3", 
    "value c" 
}; 

/* THIS IS THE IMPORTANT PART: */ 
/* Replace list with kvp.Value */ 
list = list.SelectMany( 
     i => i.Split(',').Select(v => v.Trim()) 
     ).ToList(); 

foreach (var item in list) 
    Console.WriteLine(item); 

Выход:

значение значение
б
значение 1
значение 2
значение 3
значение с

Чтобы использовать это в коде:

foreach (var kvp in dict) 
{ 
    if (kvp.Key == "STAR-016") 
    { 
     var newList = 
      kvp.Value.SelectMany(
       i => i.Split(',').Select(v => v.Trim()) 
      ); 
     kvp.Value.Clear(); 
     kvp.Value.AddRange(newList); 
    } 
} 

Благодаря @Mudu за указание на простой i => синтаксис

+1

+1 для использования LINQ, который более изящный. Однако, будет 'i => i.Split (','). Выберите (s => s.Trim())' тоже не слишком хорошо? http://msdn.microsoft.com/en-us/library/b873y76a.aspx –

+0

Хе-хе ... да, это правда. Не переставал думать слишком сильно. – JDB

+0

На самом деле нет смысла перебирать «Словарь», чтобы найти конкретное значение ключа. Я имею в виду, что это то, что «Словарь» является буквальным. – juharr

1

(редактирование: juharr-х https://stackoverflow.com/a/14875503/17713 делает в основном то же самое со встроенными функциями LINQ и более функциональным стилем, который часто более выразителен при описании фактического представления м)

я бы на подходе с yield, что не изменяет оригинальную коллекцию.Вот пример кода, который работает на List<string> orig, который также может быть в словаре:

public static void Main() 
{ 
    List<string> orig = new List<string>() 
    { 
     "value a", 
     "value b", 
     "value c", 
     "value 1, value 2, value 3", 
     "value d" 
    }; 

    var result = Flatten(orig).ToList(); 

    foreach(string s in result) 
    { 
     Console.WriteLine(s); 
    } 
} 

private static IEnumerable<string> Flatten(IList<string> orig) 
{ 
    foreach(string s in orig) 
    { 
     // split anyway, if there's no colon you just get a one-element 
     // array containing s, see 
     // http://msdn.microsoft.com/en-us/library/b873y76a.aspx 
     foreach(string v in s.Split(',')) 
     { 
      yield return v.Trim(); 
     } 
    } 
} 

В словаре, вы могли бы заменить результат с первоначальным значением:

dict["STAR-016"] = Flatten(dict["STAR-016"]).ToList() 

примечание стороны: Приведенный выше код находит STAR-016, а не используя foreach, который работает медленнее. Если вы не сократили код, и на самом деле вы просто смотрите вверх STAR-016 Я бы рекомендовал вам использовать этот способ поиска в словаре.

2

Вы должны быть в состоянии сделать это с помощью одной строки, используя SelectMany.

dict["STAR-016"] = dict["STAR-016"].SelectMany(s=>s.Split(',')).ToList(); 

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

+0

+1 для 'SelectMany' - я думал о« flatMap »Scala, но не знал о« SelectMany »как эквивалент LINQ. –

+0

+1 Это гораздо более простой синтаксис, если OP не нужно перебирать словарь. – JDB

+0

@ Cyborgx37 это можно даже использовать, если вы зацикливаете словарь. Просто замените 'dict ["STAR-016"] 'на' kvp.Value' – juharr

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