比较字典的键和另一个字典的值

时间:2018-07-20 08:47:18

标签: c# linq dictionary

我有两个字典,都属于Dictionary<string, List<List<string>>类型。 我想从词典1中选择与词典2中的值/条目匹配的条目范围。

例如字典1的键为01, 01.1,而字典2的键为01, 01.1.则具有匹配值1

首先,我从字典2的键1处获得条目,如下所示:

var dictList = (from entry in DbDict
                where entry.Key == id.ToString() // id = 1
                select entry).ToList();

我试图通过linq选择这些,如下所示:

var matchingEntries = (from entry in ExcelDict
                       where ExcelDict.Keys.Equals(dictList[0].Value)
                       select entry).ToList();

并尝试了更多方法,但不会返回任何结果。

如何从字典1中获得值对的范围,字典1的键与字典2中的值匹配?

编辑1:

Dictionary 1: 
Key     Value
01      "these", "are"
        ..., ...
01.1    "just", "some"
        ..., ...
02      "sample", "values"
        ..., ...

Dictionary 2:
Key     Value
1       "01", "01.1"
        "foo", "bar"
        ..., ...                
2       "02", "02.21"
        "value1" "value2"

编辑2:

预期输出:

"01", "01.1"
"foo", "bar"

Edit3:

注释中要求的可编译输入。这正是我要处理的结构:

var dict1 = new Dictionary<string, List<List<string>>>();

dict1.Add("01", new List<List<string>> { new List<string> { "these" }, new List<string> { "are" } });
dict1.Add("01.1", new List<List<string>> { new List<string> { "just" }, new List<string> { "some" } });
dict1.Add("02", new List<List<string>> { new List<string> { "sample" }, new List<string> { "values" } });


var dict2 = new Dictionary<string, List<List<string>>>();
dict2.Add("1", new List<List<string>> { new List<string> { "01", "01.1" }, new List<string> { "foo", "bar" } });
dict2.Add("2", new List<List<string>> { new List<string> { "02", "value1" }, new List<string> { "02.21", "value2" } });

编辑4:

对不起,您的回复很晚。高朗·戴夫(Gaurang Dave)在评论中的建议和被接受的答案都对我有用。谢谢大家的帮助!

3 个答案:

答案 0 :(得分:4)

您写道:

  

我想从字典1中选择匹配的条目范围   字典2中的值/条目。

在Edit2的输出中,您似乎想从Dictionary 2中获取。您对并没有做任何事情。每个值都是一个List<List<string>>。在您的示例中,键1的值的第一列表中的所有字符串在字典1中都有对应的键。显然,这是确定完整值在输出中的条件。

具有键2的值的第一个列表包含一个不是字典1中的键的元素。因此,输出中没有任何值。

不清楚:如果第二个列表而不是第一个列表匹配,该怎么办?

Key     Value
3       "foo", "bar"
        "01", "01.1"

这也是您的最终结果吗?

不清楚:您是否想要List<List<string>>作为结果,还是想要一个具有所有匹配值的大List<string>?重复值呢?

假设您只想检查列表列表中的第一个列表:

我们将仅查看字典2中的值,这些键将被丢弃。然后从该值集合的每个列表中选取第一个(如果有),并作为一个单独的属性记住完整列表。

当然,空列表不应出现在最终结果中,因此,我们仅保留那些具有第一个元素的列表:

// Only use the values of dictionary 2:
IEnumerable<List<List<string>>> dict2Values = dictionary2.Values

// then for easy comparison extract the first list
var separatedFirstList = dict2Values.Select(listOfLists=> new
{
     FirstList = listOfLists.FirstOrDefault(), // this is a List<string> or null
     AllLists = listOfLists,    // original List<List<string>> where FirstList is the first
})

// keep only the elements that have a first list:
.Where(stringListWithFirstElement => stringListWithFirstElement.FirstList != null);

现在,我们已将示例字典转换为:

{
    FirstString = {"01", "01.1"},
    FullList =    {"01", "01.1"}, {"foo", "bar"}, {...}, {...},
},
{
    FirstString = {"02", "02.21"},
    FullList =    {"02", "02.21"}, {"value1" "value2"}, ...
},
{
     FirstString = ...,
     FullList = ...,
},
...

根据此序列,我们只想保留FirstString中的WHERE ALL元素是Dictionary 1的键:

IEnumerable<string> keysDictionary1 = dictionary1.Keys;
var matchingItems = separatedFirstList
    .Where(item => item.FirstList.All(txt => keysDictionary1.Contains(txt));

您会看到“哪里”和“全部”。

结果:

{
    FirstString = {"01", "01.1"},
    FullList =    {"01", "01.1"}, {"foo", "bar"}, {...}, {...},
},
...

具有FirstString = {"02", "02.21"}的那个元素被删除,因为不是firstString的所有元素都在字典1中,因此

最后:摆脱FirstString:

List<List<String>> finalResult = matchingItems
    .Select(matchingItem => matchingItem.FullList);

或者如果您希望结果为一个List<String>

List<string> finalResult = matchingItems.SelectMany(matchingItem => matchingItem.FullList);

TODO:考虑创建一个大的LINQ语句。由于中间步骤使用延迟执行,因此我不确定这是否会提高性能。但是,我确信它会降低可读性。

答案 1 :(得分:2)

似乎您正在使用linq寻找join

var result = from d1 in dict1
             join d2 in dict2
             on double.Parse(d1.Key) equals double.Parse(d2.Key)
             select d2.Value;

在上述查询中,我们通过相等的键(通过将键解析为数字)来连接两个字典,并为每个匹配项从第二个字典中选择Value作为匹配项的结果。

答案 2 :(得分:0)

这将为您提供想要的东西:

var result = dict2
            .Select(kvp => kvp.Value)
            .Where(list => list.Where(l => l.Join(dict1.Keys, s1 => s1, s2 => s2, (s1, s2) => s1).Count() == l.Count).Count() > 0)
            .ToList();