7

I have a source of data which contains 3 different values like below,

List<Configuration> lst = new List<Configuration>
        {
            new Configuration{Name="A", Config="X", Value="1"},
            new Configuration{Name="A", Config="X", Value="2"},
            new Configuration{Name="B", Config="Y", Value="2"}
        };

 public class Configuration
{
    public string Name { get; set; }
    public string Config { get; set; }
    public string Value { get; set; }
}

Here I want to iterate to the entire source and want to keep "Name" value as a KEY and "Config" & "Value" into a "NameValueCollection".

For this I am taking a dictionary like below,

var config = new Dictionary<string, NameValueCollection>();

But while adding to this dictionary I m encounter 2 issues,

foreach(var c in lst)
        {
            config.Add(c.Name, new NameValueCollection { c.Config, c.Value });
        }
  1. Duplicate key (Name="A")
  2. this line giving error, new NameValueCollection { c.Config, c.Value });

Note - I want both 1 and 2 for X (in case of of duplicate key)

Is there any better C# collection or how to resolve above error.

Thanks!

user584018
  • 10,186
  • 15
  • 74
  • 160
  • 3
    What do you expect to see if there is duplicate keys? Both 1 and 2 for X? Or maybe latest value? We don't know – Sergey Berezovskiy Apr 26 '17 at 08:41
  • yes, both 1 and 2 for X – user584018 Apr 26 '17 at 08:43
  • http://stackoverflow.com/questions/10089850/c-sharp-dictionary-how-to-add-multiple-values-for-single-key –  Apr 26 '17 at 08:44
  • I am curious to know what kind of problem are you trying to solve with this NameValueCollection approach. It seems that your first data structure (`List`) is a lot better for many tasks – Steve Apr 26 '17 at 08:48
  • I don't have direct data like "List", NameValueCollection is for some other purpose (where we have duplicate key X and their value 1 & 2) – user584018 Apr 26 '17 at 08:50

4 Answers4

6

You can use dictionary of lookups (it represents a collection where key is mapped to multiple values):

var config = lst.GroupBy(cfg => cfg.Name)
                .ToDictionary(g => g.Key, 
                              g => g.ToLookup(cfg => cfg.Config, cfg => cfg.Value));

Type of config will be

Dictionary<string, ILookup<string, string>>

Accessing values:

config["A"]["X"] // gives you IEnumerable<string> with values ["1","2"]
Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
3

Try this:

        List<Configuration> lst = new List<Configuration>
        {
            new Configuration{Name="A", Config="X", Value="1"},
            new Configuration{Name="A", Config="X", Value="2"},
            new Configuration{Name="B", Config="Y", Value="2"}
        };
        var config = new Dictionary<string, NameValueCollection>();
        NameValueCollection temp = new NameValueCollection();
        foreach (var c in lst)
        {
            if(config.TryGetValue(c.Name, out temp)){
                config[c.Name].Add(c.Config,c.Value);
            }
            else{
                config.Add(c.Name, new NameValueCollection { {c.Config,c.Value } });
            }
        }
Yashar Aliabbasi
  • 2,663
  • 1
  • 23
  • 35
  • Unfortunately this is inefficient. A dictionary is very effficient if you lookup keys. But you use the collection that is returned from the `Keys` property. This property fills a collections with all keys. Then `config.Keys.Contains(c.Name)` compares all strings in this collection with the given name which is `O(n)`. So you lose the lookup performance of the dictionary. Instead use `config.TryGetValue` – Tim Schmelter Apr 26 '17 at 09:20
  • Thank you @TimSchmelter ! :) – Yashar Aliabbasi Apr 26 '17 at 09:41
  • the body of your `if` is incorrect, it must be: `config[c.Name].Add(c.Config, c.Value);`. But even better is: `temp.Add(c.Config, c.Value)` to avoid another lookup – Tim Schmelter Apr 26 '17 at 10:04
2

A NameValueCollection contains multiple names and values, because its a collection. So you can't iniialize it in your way. But you can use it to group all duplicate Names into the same collection. I'd use Dictionary<k,v>.TryGetValue:

var config = new Dictionary<string, NameValueCollection>();

foreach (Configuration c in lst)
{
    NameValueCollection nvc;
    if(!config.TryGetValue(c.Name, out nvc))
    {
        nvc = new NameValueCollection();
        config.Add(c.Name, nvc);
    }
    nvc.Add(c.Config, c.Value);
}
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
0

try this: in Dictionary class no need to check the value is duplicate or not; if its the firs time will be add. if is second time it will be update.

   List<Configuration> lst = new List<Configuration>
    {
        new Configuration{Name="A", Config="X", Value="1"},
        new Configuration{Name="A", Config="X", Value="2"},
        new Configuration{Name="B", Config="Y", Value="2"}
    };
        var config = new Dictionary<string, NameValueCollection>();
        foreach (var c in lst)
        {
            config[c.Name] = new NameValueCollection { { c.Config, c.Value } };

        }
Shahrooz Ansari
  • 2,637
  • 1
  • 13
  • 21