简体   繁体   English

C#:合并字典和列表

[英]C# : Merging Dictionary and List

I have a List of String like 我有一个像这样的String List

List<String> MyList=new List<String>{"A","B"};

and a 和一个

Dictionary<String, Dictionary<String,String>> MyDict=new Dictionary<String,Dictionary<String,String>>(); 

which contains 其中包含

 Key      Value
          Key     Value

   "ONE"        "A_1"  "1"
                "A_2"  "2"
                "X_1"  "3"
                "X_2"  "4"
                "B_1"  "5"

    "TWO"       "Y_1"  "1"
                "B_9"  "2"
                "A_4"  "3"
                "B_2"   "6"
                "X_3" "7"

I need to merge the the list and Dictionary into a new Dictionary 我需要将列表和字典合并到新字典中

 Dictionary<String,String> ResultDict = new Dictionary<String,String>()

The resulting dictionary contains 结果字典包含

Key Value

"A_1"   "1"
"A_2"   "2"
"B_1"   "5"
"A_4"   "3"
"B_2"   "6"
"X_2"   "4"
"X_3"   "7"

Merge rule 合并规则

  1. First add the items which has a substring equals to any item in the list. 首先添加其子字符串等于列表中任何项目的项目。
  2. Then Merge the items in the "MyDict" so the result should not contain duplicate keys as well as duplicate values. 然后合并“ MyDict”中的项目,使结果不应包含重复的键和重复的值。

Here is my source code. 这是我的源代码。

        Dictionary<String, String> ResultDict = new Dictionary<string, string>();
        List<String> TempList = new List<string>(MyDict.Keys);
        for (int i = 0; i < TempList.Count; i++)
        {
            ResultDict = ResultDict.Concat(MyDict[TempList[i]])
                                              .Where(TEMP => MyList.Contains(TEMP.Key.Contains('_') == true ? TEMP.Key.Substring(0, TEMP.Key.LastIndexOf('_'))
                                                                                                            : TEMP.Key.Trim()))
                                              .ToLookup(TEMP => TEMP.Key, TEMP => TEMP.Value)
                                              .ToDictionary(TEMP => TEMP.Key, TEMP => TEMP.First())
                                              .GroupBy(pair => pair.Value)
                                              .Select(group => group.First())
                                              .ToDictionary(pair => pair.Key, pair => pair.Value);            }
        for (int i = 0; i < TempList.Count; i++)
        {
            ResultDict = ResultDict.Concat(MyDict[TempList[i]])
                                              .ToLookup(TEMP => TEMP.Key, TEMP => TEMP.Value)
                                              .ToDictionary(TEMP => TEMP.Key, TEMP => TEMP.First())
                                              .GroupBy(pair => pair.Value)
                                              .Select(group => group.First())
                                              .ToDictionary(pair => pair.Key, pair => pair.Value);
        }

its working fine, but I need to eliminate the two for loops or at least one (Any way to do this using LINQ or LAMBDA expression) 其工作正常,但我需要消除两个for循环或至少一个循环(使用LINQ或LAMBDA表达式的任何方法)

Here's one way you could do it with LINQ and lambdas, as requested: 这是您可以按照要求使用LINQ和lambdas的一种方法:

var keysFromList = new HashSet<string>(MyList);
var results =
    MyDict.Values
          .SelectMany(x => x)
          .OrderBy(x => {
                            int i = x.Key.LastIndexOf('_');
                            string k = (i < 0) ? x.Key.Trim() 
                                               : x.Key.Substring(0, i);
                            return keysFromList.Contains(k) ? 0 : 1;
                        })
          .Aggregate(new {
                             Results = new Dictionary<string, string>(),
                             Values = new HashSet<string>()
                         },
                     (a, x) => {
                                   if (!a.Results.ContainsKey(x.Key)
                                           && !a.Values.Contains(x.Value))
                                   {
                                       a.Results.Add(x.Key, x.Value);
                                       a.Values.Add(x.Value);
                                   }
                                   return a;
                               },
                     a => a.Results);

Loop wise this code is simpler, but not Linq: 明智的循环此代码更简单,但不是Linq:

public static Dictionary<string, string> Test()
{
    int initcount = _myDict.Sum(keyValuePair => keyValuePair.Value.Count);

    var usedValues = new Dictionary<string, string>(initcount); //reverse val/key
    var result = new Dictionary<string, string>(initcount);
    foreach (KeyValuePair<string, Dictionary<string, string>> internalDicts in _myDict)
    {
        foreach (KeyValuePair<string, string> valuePair in internalDicts.Value)
        {
            bool add = false;
            if (KeyInList(_myList, valuePair.Key))
            {
                string removeKey;
                if (usedValues.TryGetValue(valuePair.Value, out removeKey))
                {
                    if (KeyInList(_myList, removeKey)) continue;
                    result.Remove(removeKey);
                }
                usedValues.Remove(valuePair.Value);
                add = true;
            }
            if (!add && usedValues.ContainsKey(valuePair.Value)) continue;
            result[valuePair.Key] = valuePair.Value;
            usedValues[valuePair.Value] = valuePair.Key;
        }
    }
    return result;
}

private static bool KeyInList(List<string> myList, string subKey)
{
    string key = subKey.Substring(0, subKey.LastIndexOf('_'));
    return myList.Contains(key);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM