TCL - 将 2 个列表重新映射为一个列表

问题描述 投票:0回答:1

我有 N 个列表,即 2 个这样的列表: { a { 1 2 3 } } 和 { b { 4 5 6 } } 我想重新映射值以获得此列表 { {{ a 1 } {b 4 }} {{ a 2 } {b 5 }} {{ a 3 } {b 6 }} }

我对 tcl 不太熟练(8.5,我无法升级),所以我正在努力寻找一个好的算法来通过从 2 个或更多列表开始以及每个列表的第二部分的编号来完成上述操作可以是变量,即 {{a { 1 2 3 4 5 ..n}}

有什么帮助吗?

tcl
1个回答
0
投票

我不知道你为什么想要这种转换,但据我了解你想要什么,这会做到这一点:

proc weirdshuffle lists {
    set tags        {}
    set iterators   {}

    foreach l $lists {
        lassign $l tag vals
        lappend tags $tag
        lappend iterators $tag $vals
    }

    lmap {*}$iterators {
        lmap tag $tags {
            list $tag [set $tag]
        }
    }
}

proc weirdshuffle8.5 lists {
    set tags        {}
    set iterators   {}

    foreach l $lists {
        lassign $l tag vals
        lappend tags $tag
        lappend iterators $tag $vals
    }

    set res {}
    foreach {*}$iterators {
        set tmp {}
        foreach tag $tags {
            lappend tmp [list $tag [set $tag]]
        }
        lappend res $tmp
    }
    set res
}

puts [weirdshuffle8.5 {
    {a {1 2 3}}
    {b {4 5 6}}
    {c {7 8 9}}
}]

使用

lmap
版本更容易理解它的功能,但该命令首先出现在 Tcl 8.6 中,因此
weirdshuffle8.5
是一个显式处理循环累加器的实现。

核心思想是利用

foreach
(和
lmap
)支持不同值列表上的多个迭代器这一事实,并构造迭代器和列表的列表,然后在这些上运行
lmap
(或
foreach
) .

对于偏执者来说,重要的是要认识到这样做会根据传入列表的值在

weirdshuffle
中创建(或覆盖)变量,如果其中一个与 proc 使用的变量冲突,可能会破坏事情。以一些视觉混乱为代价,可以通过在数组中设置索引来避免这种情况:

proc weirdshuffle_safe lists {
    set tags        {}
    set iterators   {}

    foreach l $lists {
        lassign $l tag vals
        lappend tags t($tag) $tag
        lappend iterators t($tag) $vals
    }

    lmap {*}$iterators {
        lmap {tag name} $tags {
            list $name [set $tag]
        }
    }
}

这也可以防止更病态的情况,即迭代器变量看起来像其他名称空间中的完全限定变量:

{::foo::bar {1 2 2}} {::global {4 5 6}}
否则可以在过程调用框架之外设置任意状态。如果您无法控制这些标签值(示例中的
a
b
),那么我会使用
_safe
变体来确保。

© www.soinside.com 2019 - 2024. All rights reserved.