我有一个清单:
set aList {aa aa aa bb bb cc cc cc cc aa aa bb cc cc cc cc}
我想生成一个类似于:
的摘要3 aa 2 bb 4 cc 2 aa 1 bb 4 cc
我可以使用foreach循环生成摘要,但我正在寻找更好的解决方案。
答案 0 :(得分:0)
你要求的基本上是一个RLE编码命令。我不知道,但可能有一个地方 - 它是否适合你的格式是另一回事。在维基上有一个名为RLE的页面,但这只是一个用户签名。
否则,在处理迭代结构时很难避免迭代命令。你可以试试递归:
set aList {aa aa aa bb bb cc cc cc cc aa aa bb cc cc cc cc}
proc summarize {result theList} {
if {[llength $theList] eq 0} {
return $result
} else {
summarize {*}[count $result $theList 1]
}
}
proc count {result theList theCount} {
set theList [lassign $theList theToken]
if {$theToken eq [lindex $theList 0]} {
count $result $theList [incr theCount]
} else {
list [lappend result $theCount $theToken] $theList
}
}
summarize [list] $aList
简短评论:summarize
函数使用两个列表,一个偶数大小(最初为空)的计数和标记列表(result
)和一个未处理的标记列表(theList
)。如果theList
为空,则result
列表是操作的结果。如果theList
中至少有一个令牌,我们会通过计算theList
头部中有多少相同的令牌来准备一对新的类似列表,并总结这两个列表。对于每个应用程序,result
将更长一对,theList
将缩短一定数量的令牌≥1。
它可以象征性地表示(使用准ML表示法)
总结(R,Ø)→R
总结(R,L)→总结计数(R,L,1)
count
函数使用相同的两个列表,并且还有一个计数(最初为1:如果theList
不为空,我们将始终至少有一个令牌来计算)。它在theList
的头部中断了一个标记,并将其与(现在缩短的)theList
进行比较。如果theToken
与theList
中的第一个令牌相同,我们会增加theCount
并再次应用count
。如果不是,我们将result
与theCount
和theToken
一起扩展,并计算了一种令牌(执行然后通过调用层返回summarize
)。
请注意,使用count
的空列表调用theList
会导致无限循环:除非theList
中有令牌,否则摘要永远不会调用它。
count(R,(T ::(T :: L)),N)→count(R,(T :: L),N + 1)
count(R,( a :: L),N)→((R @(N ::( a ::Ø))),L)
答案 1 :(得分:0)
以下功能贯穿列表并保持当前项目的计数:
proc group_identical {slist} {
set newlist {}
set current [lindex $slist 0]
set count 0
foreach ele $slist {
if { ![string compare $ele $current] } { ;# same as current;
incr count
} else { ;# new element
lappend newlist $count $current
set current $ele
set count 1
}
}
lappend newlist $count $current
return $newlist
}
set aList {aa aa aa bb bb cc cc cc cc aa aa bb cc cc cc cc}
puts [group_identical $aList]
输出:
3 aa 2 bb 4 cc 2 aa 1 bb 4 cc