在 Tcl 中创建子列表和排序

create sublist and sort in Tcl

我需要对随机排列的句子进行排序。句子中的每个单词都有一个索引值。 例如 设置句子“will2 out4 Things1 work3” Output="事情会解决的"

我尝试使用 lsort -index 1 {{will 2} {out 4} {Things 1} {work 3}} 这将输出为 {Things 1} {will 2} {work 3} {out 4} 我需要帮助来创建子列表并拆分输入语句以使其能够进行排序。

你必须先把你的单词变成一个可以用 lsort 排序的成对列表,然后只提取单词部分 re-join 把它们变成一个句子。这是所谓的 decorate-sort-undecorate 操作的细微变化。

#!/usr/bin/env tclsh

set sentence "will2 out4 Things1 work3"

# Turn sentence into a list of pairs of the words and numbers
set pairs [lmap word [split $sentence] {
    regexp {([[:alpha:]]+)(\d+)$} $word -> w n
    list $w $n    
}]

# Sort based on number much like you're doing in your question
set pairs [lsort -index 1 -integer $pairs]

# And re-join the first elements of the pairs
set sentence [join [lmap pair $pairs { lindex $pair 0 }]]

puts $sentence

如果你在没有中间变量的情况下一步完成所有操作,它被称为 Schwartzian Transform(尽管在这种情况下我认为可读性会受到影响):

set sentence [join [lmap pair [lsort -index 1 -integer \
                                   [lmap word [split $sentence] {
                                       regexp {([[:alpha:]]+)(\d+)$} $word -> w n
                                       list $w $n
                                   }]] { lindex $pair 0 }]]

如果你的句子有九个或更少的单词,你可以用lmap反转每个单词,对反转的单词排序,然后un-reverse。

set sentence "will2 out4 Things1 work3"
                                    
set ecnetnes [lmap word $sentence {string reverse $word}]

set sorted_ecnetnes [lsort $ecnetnes]

set sorted_sentence [lmap word $sorted_ecnetnes {string range [string reverse $word] 0 end-1}]

--> Things will work out

可以使用 regexp 将单词解析为其文本和索引部分(\D 匹配 non-digit,\d 匹配数字):

regexp {(\D+)(\d+)} $word -> text index

然后您可以通过转换列表或制作用于排序的辅助列表来使用它。

就性能而言,这两种技术在您的样本输入上非常相似(假设明显转换为过程),时间差异小于 1%。要么他们实际上做的工作量相同,要么他们在过度努力方面犯了类似的错误。

按列表转换排序

set input "will2 out4 Things1 work3"
set prepared [lmap word $input {
    lrange [regexp -inline {(\D+)(\d+)} $word] 1 end
}]
set sorted [lsort -integer -index 1 $prepared]
set output [lmap pair $sorted {
    lindex $pair 0
}]
# Converting that into a one-liner is left as an obvious exercise

使用辅助列表排序

这使用 lsort-indices 选项,告诉您列表中的值将按什么顺序排序;如果您想将该订单应用于其他东西,这很好。

set input "will2 out4 Things1 work3"
set texts [set values {}]
foreach word $input {
    regexp {(\D+)(\d+)} $word -> t v
    lappend texts $t
    lappend values $v
}
set sorted [lsort -indices -integer $values]
set output [lmap idx $sorted {
    lindex $texts $idx
}]