poco poco - 1 month ago 28
C# Question

c# linq combine 2 dictionaries

I have two

Dictionary<string, Item>
s.
Item
has a has a public property
int Level
.

I want to combine these two dictionaries where keys are unique and I want to be able to specify level on both.

Something like

dictionary 1 = all items that level < 10
dictionary 2 = all items level < 20

combine dictionary 2 with 1 (where Value.Level < 10)
if the Key is unique and the Value.Level < 20


I can easily do this with foreach loops. I can also do this with multiple linq queries.
However i can't seem to figure out how to make this one single linq query.

Edit- Per your request John here is the code with foreach

Dictionary<string, Dictionary<string, Item>> itemDictionary = new Dictionary<string, Dictionary<string, Item>>();

Dictionary<string, Item> items = new Dictionary<string,Item>();

if (itemDictionary.ContainsKey(comboBox.Text))
{
foreach (KeyValuePair<string, Item> kvp in itemDictionary[comboBox.Text])
{
if (!items.ContainsKey(kvp.Key) && kvp.Value.Level <= int.Parse(textBox.Text))
items.Add(kvp.Key, kvp.Value);
}
}

if (itemDictionary.ContainsKey(comboBox1.Text))
{
foreach (KeyValuePair<string, Spell> kvp in itemDictionary[comboBox1.Text])
{
if (!items.ContainsKey(kvp.Key) && kvp.Value.Level <= int.Parse(textBox1.Text))
items.Add(kvp.Key, kvp.Value);
}
}
var query = from s in items
orderby s.Value.Level
select s;

foreach (var i in query)
listBox.Items.Add(string.Format("{0} {1}", i.Value.Level, i.Key));

Answer

Ok, that code makes it clear what you want to accomplish. So the end result should be a dictionary comprised of the items from both dictionaries that meet the specified level. If an item exists in both dictionaries than the item from the first dictionary will be preferred. While it is possible to accomplish this in a single Linq query you would end up repeating some work. Here is what I came up with, it runs in LinqPad if you want to try it out easily.

var itemsOne = new[] {
    new { Name = "A", Level = 1 },
    new { Name = "B", Level = 2 },
    new { Name = "C", Level = 3 },
    new { Name = "D", Level = 4 }
}.ToDictionary(i => i.Name, i => i);

var itemsTwo = new[] {
    new { Name = "C", Level = 10 },
    new { Name = "D", Level = 20 },
    new { Name = "E", Level = 30 },
    new { Name = "F", Level = 40 }
}.ToDictionary(i => i.Name, i => i);

var itemsOneLevel = 3;
var itemsTwoLevel = 30;

var validFromItemsOne = (from item in itemsOne
                         where item.Value.Level <= itemsOneLevel
                         select item).ToDictionary(i => i.Key, i => i.Value);

var validFromItemsTwo = from item in itemsTwo
                        where item.Value.Level <= itemsTwoLevel
                            && !validFromItemsOne.ContainsKey(item.Key)
                        select item;

var items = validFromItemsOne
    .Concat(validFromItemsTwo)
    .ToDictionary(i => i.Key, i => i.Value);