两级飞溅TCL
two level splatter TCL
如果我在 TCL 中有一个过程或命令,参数数量可变,如果列表的元素作为输入,则可以使用 "splatter" 运算符,例如:
set a [list "ko" ]
set m [ list "ok" "bang" ]
lappend a {*}$m
但是,如果我想 "twice splatter" 怎么办?即,压平 2 个级别?按顺序使用它两次,不起作用:
set a [list "ko" ]
set m [ list [ list "ok" ] [ list "bang" ] ]
lappend a {*}{*}$m
额外字符会出错。
{*}
语法本身并没有真正扁平化列表 。展平是执行级别 activity,而参数扩展是解析级别 activity.
% set a a
% lappend a {*}{{a b} {c d}}
在此示例中,列表 {{a b} {c d}}
中的项目作为两个单独的参数拼接到命令行中:
% lappend a {a b} {c d}
a {a b} {c d}
如果您需要再展平一层,您应该在扩展“之间”使用命令:
% lappend a {*}[concat {*}{{a b} {c d}}]
a a b c d
文档:
concat,
lappend,
{*} (syntax),
Summary of Tcl language syntax
您已经注意到 {*}
(故意)没有深入两步。
您的具体示例并不能很好地说明问题,因此我建议:
set a [list "ko" ]
set m [list [list "a b" "c d"] [list "e f" "g h"]]
lappend a {*}$m
在这里,我们将 a
设置为 ko {{a b} {c d}} {{e f} {g h}}
。这不是你想要的。但我们可以这样做:
lappend a {*}[concat {*}$m]
这给出了这个:ko {a b} {c d} {e f} {g h}
。看起来不错。
但是我们真的在这里做正确的事吗?让我们用我们的超级秘密内省器 representation
命令深入了解一下:
% tcl::unsupported::representation $m
value is a list with a refcount of 4, object pointer at 0x10085ec50, internal representation 0x103016790:0x0, string representation "{{a b} {c d}}..."
% tcl::unsupported::representation [concat {*}$m]
value is a string with a refcount of 1, object pointer at 0x10085de10, internal representation 0x1030052d0:0x10085f190, string representation "{a b} {c d} {..."
呃哦!我们已经失去了列表性。这不是灾难,但这不是我们想要的。相反,我们真的应该这样做:
foreach sublist $m {
lappend a {*}$sublist
}
好吧,那是更多的代码,但保留了列表特性(如果你碰巧在叶子上有珍贵的类型,这会很好;核心 Tcl 没有这样珍贵的类型,但一些扩展有)。
我们可以比较时间:
% time {
set a [list "ko" ]
set m [list [list "a b" "c d"] [list "e f" "g h"]]
lappend a {*}[concat {*}$m]
} 10000
2.852789 microseconds per iteration
% time {
set a [list "ko" ]
set m [list [list "a b" "c d"] [list "e f" "g h"]]
foreach sublist $m {
lappend a {*}$sublist
}
} 10000
4.022959 microseconds per iteration
哦…
% time {apply {{} {
set a [list "ko" ]
set m [list [list "a b" "c d"] [list "e f" "g h"]]
lappend a {*}[concat {*}$m]
}}} 10000
2.4486125 microseconds per iteration
% time {apply {{} {
set a [list "ko" ]
set m [list [list "a b" "c d"] [list "e f" "g h"]]
foreach sublist $m {
lappend a {*}$sublist
}
}}} 10000
1.6870501 microseconds per iteration
哈!类型正确的在过程中更好(-like context)。
如果我在 TCL 中有一个过程或命令,参数数量可变,如果列表的元素作为输入,则可以使用 "splatter" 运算符,例如:
set a [list "ko" ]
set m [ list "ok" "bang" ]
lappend a {*}$m
但是,如果我想 "twice splatter" 怎么办?即,压平 2 个级别?按顺序使用它两次,不起作用:
set a [list "ko" ]
set m [ list [ list "ok" ] [ list "bang" ] ]
lappend a {*}{*}$m
额外字符会出错。
{*}
语法本身并没有真正扁平化列表 。展平是执行级别 activity,而参数扩展是解析级别 activity.
% set a a
% lappend a {*}{{a b} {c d}}
在此示例中,列表 {{a b} {c d}}
中的项目作为两个单独的参数拼接到命令行中:
% lappend a {a b} {c d}
a {a b} {c d}
如果您需要再展平一层,您应该在扩展“之间”使用命令:
% lappend a {*}[concat {*}{{a b} {c d}}]
a a b c d
文档: concat, lappend, {*} (syntax), Summary of Tcl language syntax
您已经注意到 {*}
(故意)没有深入两步。
您的具体示例并不能很好地说明问题,因此我建议:
set a [list "ko" ]
set m [list [list "a b" "c d"] [list "e f" "g h"]]
lappend a {*}$m
在这里,我们将 a
设置为 ko {{a b} {c d}} {{e f} {g h}}
。这不是你想要的。但我们可以这样做:
lappend a {*}[concat {*}$m]
这给出了这个:ko {a b} {c d} {e f} {g h}
。看起来不错。
但是我们真的在这里做正确的事吗?让我们用我们的超级秘密内省器 representation
命令深入了解一下:
% tcl::unsupported::representation $m
value is a list with a refcount of 4, object pointer at 0x10085ec50, internal representation 0x103016790:0x0, string representation "{{a b} {c d}}..."
% tcl::unsupported::representation [concat {*}$m]
value is a string with a refcount of 1, object pointer at 0x10085de10, internal representation 0x1030052d0:0x10085f190, string representation "{a b} {c d} {..."
呃哦!我们已经失去了列表性。这不是灾难,但这不是我们想要的。相反,我们真的应该这样做:
foreach sublist $m {
lappend a {*}$sublist
}
好吧,那是更多的代码,但保留了列表特性(如果你碰巧在叶子上有珍贵的类型,这会很好;核心 Tcl 没有这样珍贵的类型,但一些扩展有)。
我们可以比较时间:
% time {
set a [list "ko" ]
set m [list [list "a b" "c d"] [list "e f" "g h"]]
lappend a {*}[concat {*}$m]
} 10000
2.852789 microseconds per iteration
% time {
set a [list "ko" ]
set m [list [list "a b" "c d"] [list "e f" "g h"]]
foreach sublist $m {
lappend a {*}$sublist
}
} 10000
4.022959 microseconds per iteration
哦…
% time {apply {{} {
set a [list "ko" ]
set m [list [list "a b" "c d"] [list "e f" "g h"]]
lappend a {*}[concat {*}$m]
}}} 10000
2.4486125 microseconds per iteration
% time {apply {{} {
set a [list "ko" ]
set m [list [list "a b" "c d"] [list "e f" "g h"]]
foreach sublist $m {
lappend a {*}$sublist
}
}}} 10000
1.6870501 microseconds per iteration
哈!类型正确的在过程中更好(-like context)。