【问题标题】:Compare keys of dictionary with values of another dictionary将字典的键与另一个字典的值进行比较
【发布时间】:2018-07-20 08:47:17
【问题描述】:

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

例如字典 1 具有键 01, 01.1,字典 2 具有匹配值 01, 01.1. 在键 1

首先,我在键 1 处从字典 2 中获取条目,如下所示:

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 中获取值对的范围,其键与字典 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"

编辑3:

在 cmets 中请求的可编译输入。这正是我正在处理的结构:

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 在 cmets 中的建议和接受的答案都对我有用。感谢大家的帮助!

【问题讨论】:

  • 为什么 dict1 中的键 02 的条目没有显示在结果中?该键与dict2中的键2的值匹配!?
  • 老实说:我宁愿为您的结构构建专门的类并实现所需的功能和属性。这通常比摆弄嵌套的字典和列表更快、更容易处理。
  • @arekzyla:在 OP 中添加。
  • 使用 FooBar 示例绝不是一个好主意,因为它们可能意味着任何东西。我还不清楚你想要什么。我的意思是,从您的示例来看,它应该做的只是返回 Dict2 中 key=1 的值吗?
  • @Allix 试试这个。它适用于您在 OP 中提到的值。您可以使用您可能遇到的其他情况来检查这一点。让我知道它是否有效string selectedId = Convert.ToString(1); var result = dict2 .Where(d2 =&gt; d2.Key == selectedId) .Where(d2 =&gt; d2.Value.Any(d2lst =&gt; d2lst.Any(d2lst1 =&gt; dict1.Keys.Contains(d2lst1)))) .Select(d2 =&gt; d2.Value) .ToList();

标签: c# linq dictionary


【解决方案1】:

你写道:

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

从您在 Edit2 中的输出来看,您似乎想要从字典 2 中获取 。您没有对 Keys 做任何事情。每个值都是一个List&lt;List&lt;string&gt;&gt;。在您的示例中,具有键 1 的值的第一个列表中的所有字符串在字典 1 中都有一个相应的键。显然这是决定完整值在您的输出中的条件。

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

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

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

这也应该在您的最终结果中吗?

不清楚您想要一个List&lt;List&lt;string&gt;&gt;,还是想要一个包含所有匹配值的大List&lt;string&gt;?重复值怎么办?

假设您只想检查 List of Lists 中的第一个 List:

我们只会查看字典 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 中的Key 处,

最后:摆脱 FirstString:

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

或者如果你希望结果是一个List&lt;String&gt;

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

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

【讨论】:

    【解决方案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 作为匹配结果。

    【讨论】:

      【解决方案3】:

      这会给你你想要的:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-11-06
        • 2014-11-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多