我有一个词典列表:
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 merge
,dict update
和dict with
。我想知道我是否可以使用其中一个来简化这个字典列表转置。
特别是:我可以以某种方式自动使用原始词典中的name
和age
键,而不必再将它们写出来吗?
(我仅限于Tcl 8.5,但仍然对需要Tcl 8.6的解决方案感兴趣。)
答案 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。但请注意,在d
和a
之间插入了密钥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
命令类似,但是将字典中的所有键映射到与键名称相同的变量,并且该命令还允许指定键链以获取字典的子字典。我举个例子,但这个答案已经太久了。
答案 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;它对应于未设置的变量或缺少的密钥。)