C # Ітерація через NameValueCollection


76

У мене є NameValueCollection, і я хочу переглядати значення. На даний момент я роблю це, але, схоже, це повинен бути більш акуратний спосіб:

NameValueCollection nvc = new NameValueCollection();
nvc.Add("Test", "Val1");
nvc.Add("Test2", "Val1");
nvc.Add("Test2", "Val1");
nvc.Add("Test2", "Val2");
nvc.Add("Test3", "Val1");
nvc.Add("Test4", "Val4");

foreach (string s in nvc)
    foreach (string v in nvc.GetValues(s))
        Console.WriteLine("{0} {1}", s, v);

Console.ReadLine();

Є там?


3
Що поганого в тому, що у вас є?
Ані

2
У цьому немає нічого поганого як такого - просто я думав, що мав би мати можливість ітерації за допомогою одного циклу. Переглядаючи відповіді на даний момент, здається, це неможливо, якщо можуть бути повторювані значення ключів.
Paul Michaels

це правильно, але ви можете використовувати іншу колекцію, наприкладDictionary<string, List<string>>
Майстер тіней вакцинує

Відповіді:


102

Ви можете згладити колекцію за допомогою Linq, але це все одно foreachцикл, але тепер більш неявний.

var items = nvc.AllKeys.SelectMany(nvc.GetValues, (k, v) => new {key = k, value = v});
foreach (var item in items)
    Console.WriteLine("{0} {1}", item.key, item.value);

Перший рядок перетворює вкладену колекцію у (невкладену) колекцію анонімних об’єктів із ключем властивостей та значенням .

Це вирівнюється так, що тепер це ключ зіставлення -> значення замість ключа -> колекція значень . Приклад даних:

До:

Тест -> [Val],

Тест2 -> [Val1, Val1, Val2],

Тест3 -> [Val1],

Test4 -> [Val4]

Після:

Тест -> Валь,

Тест2 -> Val1,

Тест2 -> Val1,

Тест2 -> Val2,

Тест3 -> Val1,

Test4 -> Val4


3
Випробувано та використовуєтьсяusing System.Linq;
Джуліан

3
На випадок, якщо хтось захоче знати синтаксис vb.net:Dim items = nvc.AllKeys.SelectMany(AddressOf col.GetValues, Function(k, v) New With {.key = k, .value = v})
Endy Tjahjono

2
@EndyTjahjono легка друкарська помилка, змініть "col" на "nvp", так це стаєDim items = nvc.AllKeys.SelectMany(AddressOf nvp.GetValues, Function(k, v) New With {.key = k, .value = v})
Тім Партрідж


Що робити, якщо це порожнє значення, як мені string.emptyзамість цього просто додати add ?
Si8

83

Ви можете використовувати ключ для пошуку замість того, щоб мати два цикли:

foreach (string key in nvc)
{
    Console.WriteLine("{0} {1}", key, nvc[key]);
}

19
Зауважте, що це буде поводитися інакше, ніж код OP, якщо є ключі з декількома значеннями. Ваш код виведе "ключ значення1, значення2, значення3" , тоді як код операційної системи виведе " ключ значення1", потім "ключ значення2", потім "ключ значення3" .
LukeH

4

Тут нічого нового не можна побачити (відповідь @ Julian, поставлену мною +1, функціонально еквівалентна). Ви, будь ласка, рухайтесь по всьому.


У мене є [надмірний для цього випадку, але, можливо, відповідний] набір методів розширення у відповіді на відповідне запитання , яке дозволить вам зробити:

foreach ( KeyValuePair<string,string> item in nvc.AsEnumerable().AsKeyValuePairs() )
    Console.WriteLine("{0} {1}", item.key, item.value);

3
NameValueCollection не має AsEnumerable або як keyValuePairs
Луїс

@ Луїс Теллез. Я знаю. У тексті сказано, що я маю набір методів розширення . І це посилається на нього. І основний текст стверджує, що тут нічого нового не можна побачити, будь ласка. Це пояснює чи мені потрібно повторно пояснити?
Рубен Бартелінк,

1

Єдиний спосіб, який я знайшов, щоб уникнути вкладених циклів - використання додаткового списку для зберігання значень:

List<string> arrValues = new List<string>();
for (int i = 0; i < nvc.Count; i++)
    arrValues.AddRange(nvc.GetValues(i));
foreach (string value in arrValues)
    Console.WriteLine(value);

(Потрібен [лише] .NET 2.0 або новішої версії)


(очевидно замінено використанням, SelectManyяк і інша відповідь )
Рубен Бартелінк

@Ruben правда, але я вважаю за краще залишити цей, навіть якщо просто для історичної цінності показує, як це зробити зі старою версією .NET. :)
Майстер Тіней робить щеплення

Річ, з якою SelectManyя зіткнувся, полягає в тому, що якщо ключ має пусте значення, він не вдається. Будь-який спосіб обійти це? Дякую.
Si8

@ Si8, що саме не вдається? Теоретично просто киньте ifвиписку та перевірте, чи не має значення null, хоча якщо ваш код однолінійний, це зробить його набагато менш читабельним.
Майстер Тіней робить щеплення

Ваш метод працює з нулем, але LINQ - це не те, про що я заявляв ... вибачте за незрозуміле.
Si8


0
var enu = myNameValueCollection.GetEnumerator();
while (enu.MoveNext())
{
    string key = (string)enu.Current;
    string value = myNameValueCollection[key];
}

АБО, коли клавіші мають нульовий статус:

for (int i = 0; i < myNameValueCollection.Count; i++)
{
    string key = myNameValueCollection.GetKey(i);
    string value = myNameValueCollection.Get(i);
}

-2
foreach ( string key in nvc.Keys )
   Console.WriteLine("{0} {1}", key, nvc[key]);

Це поверне вам усі ключі та відповідні значення.


2
Ні; він не поверне повторюваних значень.
Слакс

Хіба це не дубль stackoverflow.com/a/5065986/11635, який на мілісекунди раніше (вау!) - особисто я б видалив. @Slaks буде педантичним, він дасть повторювані значення, лише з комами, що розділяють їх.
Ruben Bartelink
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.