将一个字典的键与另一个字典的值进行比较

4
我有两个字典,它们都是Dictionary<string, List<List<string>>类型。我想从字典1中选择与字典2的值/条目相匹配的条目范围。
例如,字典1具有键01、01.1,而字典2在键1处具有相应的值01、01.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中与字典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:

根据评论中的要求,提供可编译的输入内容。这正是我正在处理的结构:

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在评论中提出的建议和被接受的答案对我都有效。感谢大家的帮助!


1
为什么dict1中关键字为02的条目没有出现在结果中?这个关键字应该与dict2中关键字为2的值相匹配啊! - Georg Patscheider
2
说实话:我宁愿为您的结构构建专用类并实现所需的函数和属性。这通常比摆弄嵌套的字典和列表更快且更容易处理。 - Rob
1
@arekzyla:已添加在原帖中。 - Allix
2
使用FooBar示例从来都不是一个好主意,因为它们可能意味着任何事情。我仍然不太清楚你想要什么。我的意思是,从你的例子中,它只是返回Dict2中key=1的值吗? - MineR
1
@Allix 试试这个。对于你在 OP 中提到的值,它是有效的。您可以使用其他可能存在的场景进行检查。让我知道它是否起作用了。`string selectedId = Convert.ToString(1); var result = dict2 .Where(d2 => d2.Key == selectedId) .Where(d2 => d2.Value.Any(d2lst => d2lst.Any(d2lst1 => dict1.Keys.Contains(d2lst1)))) .Select(d2 => d2.Value) .ToList();` - Gaurang Dave
显示剩余17条评论
3个回答

5
您写道:
您想从字典1中选择与字典2的值/条目匹配的条目范围。
从Edit2的输出来看,似乎您想从字典2中取出值。 您没有使用Keys。每个值都是List >。 在您的示例中,值中第一个列表中的所有字符串都与字典1中的某个键对应。 显然,这是决定完整值是否在输出中的条件。
值为2的该值的第一个列表中有一个元素不是字典1中的键。 因此,值中的任何内容都不在输出中。
不清楚:如果第二个列表与第一个列表匹配会怎样?
Key     Value
3       "foo", "bar"
        "01", "01.1"

这个在你的最终结果中也应该包含吗?

不清楚,您是想要一个List<List<string>>作为结果,还是想要一个包含所有匹配值的大List<string>?重复值怎么处理?

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

我们只看Dictionary 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中的所有元素都是Dictionary 1的键的元素:

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

你看到了Where和All。
结果:
{
    FirstString = {"01", "01.1"},
    FullList =    {"01", "01.1"}, {"foo", "bar"}, {...}, {...},
},
...

由于字典1中并不包含firstString中所有的键,因此FirstString = {"02", "02.21"}被移除。

最后:删除FirstString:

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

如果您希望结果是一个List<String>:

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 作为匹配结果。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接