82

I have a NameValueCollection, and want to iterate through the values. Currently, I’m doing this, but it seems like there should be a neater way to do it:

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();

Is there?

Julian
  • 33,915
  • 22
  • 119
  • 174
Paul Michaels
  • 16,185
  • 43
  • 146
  • 269

8 Answers8

114

You can flatten the collection with Linq, but it's still a foreach loop but now more implicit.

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);

The first line, converts the nested collection to a (non-nested) collection of anonymous objects with the properties key and value.

It's flatten in the way that it's now a mapping key -> value instead of key -> collection of values. The example data:

Before:

Test -> [Val],

Test2 -> [Val1, Val1, Val2],

Test3 -> [Val1],

Test4 -> [Val4]

After:

Test -> Val,

Test2 -> Val1,

Test2 -> Val1,

Test2 -> Val2,

Test3 -> Val1,

Test4 -> Val4

Community
  • 1
  • 1
Julian
  • 33,915
  • 22
  • 119
  • 174
  • 3
    Tested and using `using System.Linq;` – Julian Feb 21 '11 at 13:30
  • 3
    In case someone wants to know the vb.net syntax: `Dim items = nvc.AllKeys.SelectMany(AddressOf col.GetValues, Function(k, v) New With {.key = k, .value = v})` – Endy Tjahjono Jan 30 '13 at 09:06
  • 2
    @EndyTjahjono slight typo, change "col" to "nvp" so it becomes `Dim items = nvc.AllKeys.SelectMany(AddressOf nvp.GetValues, Function(k, v) New With {.key = k, .value = v})` – Tim Partridge Sep 13 '13 at 17:00
  • [Wouldn't `v` simply refer to the index of the current key?](https://msdn.microsoft.com/en-us/library/bb549142(v=vs.100).aspx#parameters) – Drazen Bjelovuk Feb 20 '16 at 06:56
  • What if it's a blank value, how do I just get add `string.empty` instead? – Si8 May 08 '18 at 17:12
  • what is a blank value? `null`? – Julian May 08 '18 at 20:03
  • Alternatively: `nvc.AllKeys.Select(k => $"{k}={nvc[k]}")`. Formats as a key and its comma-separated values. – Suncat2000 Sep 13 '21 at 21:35
  • This way is too inefficient! using AllKeys, SelectMany, GetValues, Creating new anonym/dynamic object.... too much to just enumerate a simple collection! – S.Serpooshan Jun 15 '23 at 06:22
94

You can use the key for lookup instead of having two loops:

foreach (string key in nvc)
{
    Console.WriteLine("{0} {1}", key, nvc[key]);
}
Fredrik Mörk
  • 155,851
  • 29
  • 291
  • 343
  • 19
    Note that this will behave differently to the OP's code if there are any keys with multiple values. Your code will output *"key value1,value2,value3"*, whereas the OP's code would output *"key value1"* then *"key value2"* then *"key value3"*. – LukeH Feb 21 '11 at 14:27
4

Nothing new to see here (@Julian's +1'd by me answer is functionally equivalent), y'all move along y'all please.


I have an [overkill for this case but possibly relevant] set of extension methods in an answer to a related question, which would let you do:

foreach ( KeyValuePair<string,string> item in nvc.AsEnumerable().AsKeyValuePairs() )
    Console.WriteLine("{0} {1}", item.key, item.value);
Community
  • 1
  • 1
Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
  • 3
    NameValueCollection does not have AsEnumerable or as keyValuePairs – Luis Tellez Mar 04 '13 at 14:52
  • @Luis Tellez. I know. The text says **I have a set of extension methods**. And it links to it. And the body text is flagging that there is nothing new to see here please. Does this clarify or do I need to re-explain? – Ruben Bartelink Mar 04 '13 at 16:08
  • You can make an enumerable as `IEnumerable> e = nvc.AllKeys.Select(k => new KeyValuePair(k, nvc[k]))`. Another stumbling point brought to you by Microsoft. – Suncat2000 Sep 13 '21 at 21:41
2
var enu = myNameValueCollection.GetEnumerator();
while (enu.MoveNext())
{
    string key = (string)enu.Current;
    string value = myNameValueCollection[key];
}

OR when keys nullable:

for (int i = 0; i < myNameValueCollection.Count; i++)
{
    string key = myNameValueCollection.GetKey(i);
    string value = myNameValueCollection.Get(i);
}
Dmitry Shashurov
  • 1,148
  • 13
  • 11
1

I think this is simpler: VB.NET

For i As Integer = 0 To nvc.Count - 1
   Console.Write("No", "Key", "Value")
   Console.Write(i, nvc.GetKey(i), nvc.Get(i))
Next

C#:

for (int i = 0; i <= nvc.Count - 1; i++)
{
    Console.Write("No", "Key", "Value");
    Console.Write(i, nvc.GetKey(i), nvc.Get(i));
}
Hannington Mambo
  • 998
  • 2
  • 13
  • 28
1

The only way I found to avoid the nested loops is using additional List to store the values:

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);

(Requires [only] .NET 2.0 or later)

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
Shadow The GPT Wizard
  • 66,030
  • 26
  • 140
  • 208
  • (obviously superseded by using `SelectMany` like [the other answer](http://stackoverflow.com/a/5066541/11635)) – Ruben Bartelink Oct 03 '12 at 13:09
  • @Ruben true, but I prefer to leave this one even if just for historical value showing how to do that with old .NET version. :) – Shadow The GPT Wizard Oct 03 '12 at 13:17
  • The thing with `SelectMany` i came across is if the key has a value that's blank it fails. Any way around it? Thanks. – Si8 May 08 '18 at 18:52
  • @Si8 what exactly fails? In theory, just throw an `if` statement and check for null, though if your code is one-liner, it will make it much less readable. – Shadow The GPT Wizard May 08 '18 at 19:51
  • Your method works with the null but the LINQ doesn't is what I was stating... sorry for not clear. – Si8 May 08 '18 at 19:58
0
for (int i = 0; i < nvc.Count; i++) {
    System.Console.WriteLine(

        nvc.AllKeys[i] + " = " + nvc[i]

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

This will return you all keys and corresponding values.

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
Sachin Shanbhag
  • 54,530
  • 11
  • 89
  • 103
  • 2
    No; it won't return duplicate values. – SLaks Feb 21 '11 at 12:37
  • Isnt this a dup of http://stackoverflow.com/a/5065986/11635 which is milliseconds earlier (wow!) - personally I'd delete. @Slaks to be pedantic, it will give the duplicate values, just with commas separating them. – Ruben Bartelink Oct 03 '12 at 13:07