c#linq结合了2个字典

时间:2011-08-19 19:07:55

标签: c# linq

我有两个Dictionary<string, Item>个。 Item有一个公共财产int Level

我想将这两个字典组合在一起,其中键是唯一的,我希望能够在两者上指定级别。

这样的东西
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

我可以使用foreach循环轻松完成此操作。我也可以使用多个linq查询来完成此操作。 但是,我似乎无法弄清楚如何使这一个单一的linq查询。

编辑 - 根据您的要求John这里是带有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));

4 个答案:

答案 0 :(得分:3)

如果您可以在foreach循环中轻松完成所需的操作,那么您已经编写了代码。这告诉我foreach代码可能比复杂的LINQ查询更易读,更容易维护。

这听起来像是将foreach循环代码保留到位的完美案例。 LINQ可能更新,但并不总是意味着它更好。

答案 1 :(得分:2)

好的,该代码清楚地说明了您想要完成的任务。因此,最终结果应该是由两个词典中满足指定级别的项目组成的字典。如果两个词典中都存在一个项目,那么首选词典中的项目将是首选项目。虽然可以在单个Linq查询中完成此操作,但最终会重复一些工作。以下是我想出的内容,如果您想轻松尝试,可以在LinqPad中运行。

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

答案 2 :(得分:0)

如果我不知道你纠正了:你想要在两个字典中都有记录。无论如何,我的例子可以根据您的特定需求量身定制。

Dictionary<string, string> d1 = new Dictionary<string, string>(), d2 = new Dictionary<string, string>();
        var merged = d1
            .Join(d2, d1key => d1key.Key, d2key => d2key.Key,
                (i1, i2) => new { Key = i1.Key, Value1 = i1.Value, Value2 = i2.Value })
            .ToDictionary(t => t.Key);

合并将仅包含两个词典中存在的项目,并且能够获取每个项目的数据,例如merged [“key”]。Value1和merged [“key”]。Value2 例如,我使用了匿名类型(new {})。因此,您只能在同一方法或绑定中访问Value1和Value2,因为它们无论如何都是动态的。 在其他情况下,您应该创建一个类型来存储组合结果。

答案 3 :(得分:0)

以下是我认为适用于此方案的扩展程序。

public static class Extensions
{
    public static IDictionary<TKey, TValue> Combine<TKey, TValue>(
        this IDictionary<TKey, TValue> firstSet,
        IDictionary<TKey, TValue> secondSet,
        Func<KeyValuePair<TKey, TValue>, bool> firstFilter,
        Func<KeyValuePair<TKey, TValue>, bool> secondFilter)
    {
        return firstSet
        .Where(firstFilter)
        .Concat(secondSet.Where(secondFilter))
        .GroupBy(d => d.Key)
        .ToDictionary(d => d.Key, d => d.First().Value);
    }
}

用法:

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

itemsOne
.Combine(itemsTwo,
    kvp => kvp.Value.Level <= 3,
    kvp => kvp.Value.Level <= 30)
    .ToDictionary(d => d.Key, d=> d.Value.Level)

结果:

A 1 
B 2 
C 3 
D 20 
E 30