使用内置的 dict 命令将字典列表转换为列表字典
Transform a list of dictionaries to a dictionary of lists using the built-in dict commands
我有一个词典列表:
set personA {name Alice age 35}
set personB {name Bob age 42}
set persons [list $personA $personB]
现在我想 "transpose" 它们到一个包含列表的字典中:
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 的解决方案感兴趣。)
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 { ... }
.
字典是列表中的元素。要遍历 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
之前。
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
命令类似,只是将字典中的所有键映射到与键同名的变量,该命令还允许指定一个键链来获取字典的子字典.我想举个例子,但这个答案已经太长了。
因为 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;它对应于一个未设置的变量或一个不存在的键。)
我有一个词典列表:
set personA {name Alice age 35}
set personB {name Bob age 42}
set persons [list $personA $personB]
现在我想 "transpose" 它们到一个包含列表的字典中:
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 的解决方案感兴趣。)
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 { ... }
.
字典是列表中的元素。要遍历 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
之前。
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
命令类似,只是将字典中的所有键映射到与键同名的变量,该命令还允许指定一个键链来获取字典的子字典.我想举个例子,但这个答案已经太长了。
因为 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;它对应于一个未设置的变量或一个不存在的键。)