使用LINQ解析内部双重字典?

4

我有一个 Dictionary<double, Dictionary<double,double>>,其中内部字典的键相同,我想将其解析为以下输出:

key1,dict1val1,dict2val1
key2,dict1val2,dict2val2
...

抱歉,我应该说不需要外部键。

这是一个示例,展示了我想要的内容:

(1.0, (1.0, 1.1)),(2.0, (1.0,1.2))
(1.0, (1.1, 1.3)),(2.0, (1.1,1.4))
(1.0, (1.2, 1.5)),(2.0, (1.2,1.6))

应该输出:
1.0,1.1,1.2
1.1,1.3,1.4
1.2,1.5,1.6

有没有一种优雅的方法在LINQ中实现这个?我看到类似的问题适用于字符串字典,但是语法不适用于双精度浮点数。我已经订购了一本关于这个主题的书,但我需要尽快解决这个问题。

4
附注:使用“Double”键不是一个好主意(会出现舍入误差)。 - Dmitry Bychenko
Dictionary<double, Dictionary<double,double>> 在输出前是什么?你能给出一些例子吗? - Tim.Tang
@Dimitry - 我同意,但这就是我必须使用的。 - Michael Tracy
@Tim.Tang - 示例将是(1.0,(1.0,1.1)),(2.0,(1.0,1.2)),期望的输出将是:1.0,1.1,1.2,然后下一行为下一个内部字典集。外部键不需要。 - Michael Tracy
字典dict1中的所有键都在dict2中,反之亦然吗? dict2中是否存在不在dict1中的键? - dariogriffo
显示剩余3条评论
4个回答

1

您可以使用 SelectMany 来展开这些类型的结构:

var expanded = dictionary.SelectMany(outer => 
    outer.Value.Select(inner => new { 
       OuterKey = outer.Key, 
       InnerKey = inner.Key, 
       Value =inner.Value 
    })
);

现在你可以做以下操作:
foreach (var item in expanded)
{
  Console.WriteLine("{0},{1},{2}", item.OuterKey, item.InnerKey, item.Value);
}

接下来,如果您想提取内部键/值组合,只需执行以下操作:

var byInnerKey = expanded.ToLookup(item=> item.InnerKey, item => item.Value)

这很容易使用类似以下代码打印:

foreach (var item in byInnerKey)
{
   string values = string.Join(", ",item);
   Console.WriteLine(item.Key + ", " + values);
}

(实时示例)


注意:这里使用的是仅适用于 .net 4 及以上版本的 string.Join 方法的此重载
对于 .net 3.5 及以下版本,您可以使用循环遍历值,使用 string / StringBuilder,或显式地将它们转换为字符串数组。
string values = string.Join(", ",item.Select(d => d.ToString()).ToArray());

(实时示例3.5)


不是我想要的结果 - 请看我对Tim.Tang的回复。 - Michael Tracy
我真的不是故意想让你麻烦,非常感谢您的帮助,但我需要一个适用于net 3.5的解决方案,而且它不认可'item'作为Join中的有效参数 - 抱歉。 - Michael Tracy
不用担心,这里使用的是在4.5中添加的IEnumerable<T>重载。我会编辑一个适用于3.5版本的代码。 - SWeko
微不足道的更正:string values = string.Join(", ", item.Select(d => d.ToString()).ToArray()); - Michael Tracy

1
        var d1 = new Dictionary<double, double> { { 1.0, 1.1 } };
        var d2 = new Dictionary<double, double> { { 1.0, 1.2 } };

        var d3 = new Dictionary<double, double> { { 1.1, 1.3 } };
        var d4 = new Dictionary<double, double> { { 1.1, 1.4 } };

        var dict1 = new Dictionary<double, Dictionary<double, double>> { { 1.0, d1 }, { 2.0, d3 } };
        var dict2 = new Dictionary<double, Dictionary<double, double>>() { { 3.0, d2 }, { 4.0, d4 } };

        var keys = dict1.Values.SelectMany(dict => dict.Keys.ToList());
        var collection = keys.Select(key1 => new
        {
            Key = key1,
            Values = keys.SelectMany(key =>
                dict1.Values.Where(k1 => k1.ContainsKey(key1)).Select(k1 => k1[key1]).Union(
                dict2.Values.Where(k2 => k2.ContainsKey(key1)).Select(k2 => k2[key1]))
                ).Distinct().ToList()
        }).ToList();


        foreach (var x in collection)
        {
            Console.Write(x.Key + ": ");
            foreach (var y in x.Values)
            {
                Console.Write(y + ",");
            }
            Console.WriteLine();
        }

1
这也可以,但 SWeko 的答案更紧凑,所以我选择它作为答案。 - Michael Tracy

0

这个问题有点奇怪,而且不太合理。如果你正在使用 Dictionary<double, Dictionary<double,double>>,那么会有一个 key1、innerdictkey、innerdictvalue。

但是你在引用 dict1val1?它本身就是内部字典。

无论如何,你可以像这样循环遍历字典:

foreach(var kv in outerdic){
Console.WriteLine(kv.Key + ',' + kv.Value); // kv.Value would be a Dictionary<double, double>
Console.WriteLine(kv.Value[kv.Key]); // this would print the inner value of inner dictionary
}

抱歉,我应该用一个例子来澄清 - 请参见我对Tim.Tang的回复。 - Michael Tracy

0

如果我理解正确,这个结构看起来像这样:

dict[1.0]  ==> dictionary  [1.0] ==> 1.1
                           [1.1] ==> 1.3
                           [1.2] ==> 1.5

dict[2.0]  ==> dictionary  [1.0] ==> 1.2
                           [1.1] ==> 1.4
                           [1.2] ==> 1.6

然后我们只需遍历第一个字典,并将其与第二个字典匹配。

 var dict2 = dict[2.0];

 var lstResults = dict[1.0].Select(kvp=> String.Format("{0},{1},{2}",
                                      kvp.Key, kvp.Value, dict2[kvp.Key])
                           .ToList();

不是两个独立的字典,而是多个嵌套在一个更大的字典中,内部可以有超过两个。外部字典的键在这种情况下只是一个占位符,但它仍然需要是双精度浮点数,因为它实际上在其他地方使用(细节对于这个问题并不重要)。 - Michael Tracy
所以输出应该是 key1,dict1val1,dict2val1,...dictNval1 吗? - James Curran
对于单个内部字典中的所有值,按照key1,dict1value1...dictNval1的顺序,后跟key2,dict1value2...dictNval2等等,直到行数达到为止。 - Michael Tracy

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