使用内置的dict命令将{dlistaries列表转换为列表字典

时间:2015-06-30 15:49:07

标签: dictionary tcl

我有一个词典列表:

set personA {name Alice age 35}
set personB {name Bob age 42}
set persons [list $personA $personB]

现在我想将它们“转置”为包含列表的单个字典:

set transposedPersons {name {Alice Bob} age {35 42}}

我可以使用以下代码实现此目的:

set keys {name {} age {}}
set transposedPersons [dict map {k _} $keys {
    lmap person $persons {dict get $person $k}
}]

我并不完全了解某些内置dict命令的功能,例如dict mergedict updatedict with。我想知道我是否可以使用其中一个来简化这个字典列表转置。

特别是:我可以以某种方式自动使用原始词典中的nameage键,而不必再将它们写出来吗?

(我仅限于Tcl 8.5,但仍然对需要Tcl 8.6的解决方案感兴趣。)

2 个答案:

答案 0 :(得分:2)

foreach person $persons {
    dict for {key val} $person {
        dict lappend transposedPersons $key $val
    }
}

您要做的是将每个键下的值逐步添加到名为transposedPersons的字典中。您需要的操作是dict lappend transposedPersons $key $val

键和值取自描述人物的词典。要迭代存储在变量person中的一个字典中的键和相应值,您可以使用dict for {key val} $person { ... }

词典是列表中的元素。要遍历人物词典,请使用foreach person $persons { ... }

dict merge命令将许多字典值作为参数,并创建一个组合字典值,其中包含所有这些字典中的所有键。每个键的值是最后一个字典中具有该键的值。所以

dict merge {a 1 d 9} {b 2 d 8} {c 3 d 7}
# -> a 1 d 7 b 2 c 3

结果字典从三个不同的字典中获取总共四个键,公共键d从最后一个字典获得值7。但请注意,在da之间插入了密钥b,因为密钥的第一次出现在a之后但在b之前。< / p>

dict update命令采用字典变量,一组键变量名称映射和脚本。在评估脚本之前,将创建一组局部变量,分配新值或取消设置,具体取决于给定的字典变量中存在哪些键。如果映射中已命名的变量已存在,则如果存在键,则其值将被与键关联的值覆盖:如果不存在,则取消设置该变量。如果变量不存在,则在相应的密钥存在时将创建该变量。

在评估脚本之后,这些变量中的每一个(如果存在)都将其值插入相应键下的字典中。如果未设置该变量,则删除该键。

如果你假设

set d {firstname Sally lastname Bowles balance 2000 address {Foo Street}}
set amt 150
set script {
    if {![info exists mn]} {set mn H}
    unset addr
    if {$amt > 0} {set bal [expr {$bal-$amt}]}
}

以下调用

dict update d firstname fn middlename mn lastname ln balance bal address addr $script

大致相当于

set mappings {firstname fn middlename mn lastname ln balance bal address addr}
foreach {keyname varname} $mappings {
    if {[dict exists $d $keyname]} {
        set $varname [dict get $d $keyname]
    } else {
        unset -nocomplain $varname
    }
}
eval $script
foreach {keyname varname} $mappings {
    if {[info exists $varname]} {
        dict set d $keyname [set $varname]
    } else {
        dict unset d $keyname
    }
}

除了没有创建辅助变量(keyname等)。

在这两种情况下,d中的更新字典都包含

firstname Sally lastname Bowles balance 1850 middlename H

即。创建了一个新密钥,删除了另一个密钥,并且由于脚本中的变量发生了变化,第三个密钥的值发生了变化。

在评估命令后,映射到变量继续存在于本地范围中。

dict with命令类似,但是将字典中的所有键映射到与键名称相同的变量,并且该命令还允许指定键链以获取字典的子字典。我举个例子,但这个答案已经太久了。

文档:dictevalexprforeachifinfoset,{{3 }}

答案 1 :(得分:1)

因为Tcl会根据需要自动复制幕后的值,以便通过每个引用维护一个不可变的视图,你实际上可以这样做:

# I prefer to use “-” as my ignored variable name, and not “_”. YMMV
set transposedPersons [dict map {k -} [lindex $persons 0] {
    lmap person $persons {dict get $person $k}
}]

它确实假设$persons中的每个字典都与第一个字典具有相同的密钥集,但无论如何,这都是转换工作所必需的。 (Tcl确实有NULL;它对应于未设置的变量或缺少的密钥。)