如何检查tcl列表中的相邻值?

时间:2013-04-25 06:23:31

标签: tcl

我有一个像

这样的清单
set val [ list Fa2/0/1 Fa2/0/24 Gi1/0/13 Gi1/0/23 Gi1/1/1 Gi2/0/1 ]

现在我想把它放在循环中并在每个范围上执行一些命令

set number 0
set pattern 0
foreach n $val {
    if {$pattern == 0} {
        set current $n
        regexp {(.*/)(\d+)} $n - pattern number
        continue
    }

    regexp {(.*/)(\d+)} $n - match1 match2
    if {$match1 == $pattern} {
        #puts "someproc $current - match2"
    }
}

我无法完成这项工作,输出应该与ech对或奇异值相似

someproc Fa2/0/1 - 24
someproc Gi1/0/13 - 23
someproc Gi1/1/1 - 1       #for singular values
someproc Gi2/0/1 - 1

编辑:我有一个这样的数据列表,如:

  Gi3/0/1 Fa2/0/1 Fa2/0/24 Gi1/0/13 Gi1/0/23 Gi1/1/1 Gi2/0/1 Te1/0/1

您可以说每个数据都可以是Gi3/0/Gi2/0/Fa2/0/类型,这些数据可以在cisco swicth上覆盖某些端口范围。现在我需要执行某些命令对于一个范围。再拿上面的列表,我可以得到。

somecommand Gi3/0/1 - 1 # there is only one `Gi3/0/` with number 1.
somecommand Fa2/0/1 - 24 # range of `Fa2/0/` is 1 to 24

类似地,

somecommand Gi1/0/13 - 23
somecommand Gi1/1/1 - 1
and so on

7 个答案:

答案 0 :(得分:1)

#!/usr/bin/tcl

## Assumptions:
## The pattern will always be X/X/X
##  The values are given in list
set val_list [list Fa2/0/1 Fa2/0/24 Gi1/0/13 Gi1/0/23 Gi1/1/1 Gi2/0/1]

array set pattern {}

foreach item $val_list {
set parent [file dir $item]
set val [file tail $item]
if {[info exists pattern($parent,L)] && [info exists pattern($parent,H)]  } {
    if {$pattern($parent,L) > $val } {
    set pattern($parent,L) $val
    } elseif { $pattern($parent,H) < $val} {
    set pattern($parent,H) $val
    }
} else {  
    set pattern($parent,L) $val
    set pattern($parent,H) $val 
}
}
array set count {}
foreach pat  [array names pattern] {
set pat [lindex [split $pat ,] 0]
if {![info exists count($pat)] } {
    puts "$pat $pattern($pat,L) - $pattern($pat,H)"
    set count($pat) 1
}
}


/*The output will be 
Gi1/0 13 - 23
Fa2/0 1 - 24
Gi2/0 1 - 1
Gi1/1 1 - 1
*/

希望这是你要求的。我使用数组“count”来删除输出中的重复条目,这需要避免。希望有人能提出更好的建议。而且我们使用的是TCL的8.4版本。

答案 1 :(得分:1)

如果您不确定阵列是如何工作的,您可以编辑您发布的代码作为此代码的答案:

set number 0
set pattern 0
set current 0
set result [list Gi3/0/1 Fa2/0/1 Fa2/0/24 Gi1/0/13 Gi1/0/23 Gi1/1/1 Gi2/0/1 Te1/0/1]

foreach n [lsort $result] {
  if {$pattern == 0} {
        set current $n
    regexp {(.*/)(\d+)} $n - pattern number
    continue
  }
  regexp {(.*/)(\d+)} $n - match1 match2
    if {$match1 == $pattern} {
        set number $match2
    } else {
        puts "$current - $number"
        set pattern $match1
        set number $match2
        set current $n
    }
}

这对我有用:)

输出(请注意,我首先对列表进行了排序,因此您只需担心增加$number$match2,而不必过多担心$pattern):< / p>

Fa2/0/1 - 24
Gi1/0/13 - 23
Gi1/1/1 - 1
Gi2/0/1 - 1
Gi3/0/1 - 1

答案 2 :(得分:1)

这是我的解决方案,它不使用数组(数组没有任何问题,我的解决方案只是不需要它),并且它在一次传递中完成(即只有一个循环)。

set val [ list Fa2/0/1 Fa2/0/24 Gi1/0/13 Gi1/0/23 Gi1/1/1 Gi2/0/1 ]
set lastPattern ""
set lastNumber 0
lappend val x/1/1; # Add a trailer to ease processing

foreach item $val {
    # If item=Fa2/0/1, then pattern=Fa2/0 and number=1
    set pattern [file dirname $item]
    set number  [file tail $item]

    if {$pattern == $lastPattern} {
        # We have seen this pattern before
        puts "$pattern/$lastNumber - $number"
        set lastPattern ""
    } else {
        # This is a new pattern, print the old one if applicable then
        # save the pattern and number for later processing
        if {$lastPattern != ""} {
            puts "$lastPattern/$lastNumber - $lastNumber"
        }
        set lastPattern $pattern
        set lastNumber $number
    }
}
set val [lrange $val end-1]; # Remove the trailer

答案 3 :(得分:1)

如果要比较相邻的列表元素,使用C风格的for循环可能更清晰:

for {set i 0} {$i < [llength $val] - 1} {incr i} {
    set current [lindex $val $i]
    set next    [lindex $val [expr {$i+1}]]

    # ...
}

或者,更深奥

set l {a b c d e f g}
foreach current [lrange $l 0 end-1] \
        next    [lrange $l 1 end] {
    puts "$current $next"
}

输出

a b
b c
c d
d e
e f
f g

您甚至可以编写一个新的控件结构,类似于Ruby的each_cons

proc foreach_cons {vars list body} {
    foreach varname $vars {upvar 1 $varname $varname}
    set numvars [llength $vars]
    for {set i 0} {$i <= [llength $list]-$numvars} {incr i} {
        lassign [lrange $list $i [expr {$i + $numvars}]] {*}$vars
        uplevel 1 $body
    }
}
foreach_cons {a b c} $l {puts "$a $b $c"}
a b c
b c d
c d e
d e f
e f g

答案 4 :(得分:0)

为什么不循环使用列表的

foreach {v1 v2} $val {
     someproc $v1 $v2
}

您可以检查两个值是否相似,提取您需要的部分等。

答案 5 :(得分:0)

我想出了一个我自己的尴尬解决方案: 其中reslut是列表:

  Gi3/0/1 Fa2/0/1 Fa2/0/24 Gi1/0/13 Gi1/0/23 Gi1/1/1 Gi2/0/1 Te1/0/1

set number 0
set pattern 0
set last_element [lindex $result end]
set first_element [lindex $result 0]
foreach n $result {
    if {$pattern == 0} {
        set current $n
        set count 0
        regexp {(.*/)(\d+)} $n - pattern number
        continue
    }
    regexp {(.*/)(\d+)} $n - match1 match2
    if {$match1 == $pattern} {
    set count 0
    puts " $current - $match2"
        continue
     } else {
             if {"$last_element" == "$n"} {
             puts "$last_element"
             }
             if {"$first_element" == "$current"} {
             puts "$first_element"
             }
             incr count
             if {"$count" == 1} {
             set pattern $match1
             set current $n
             continue
             } else {
                     if {$match1 != $pattern} {
                     puts "$current"
                     }

             }
     set pattern $match1
     }
        set current $n

}

答案 6 :(得分:0)

此解决方案稍短,但需要Tcl 8.5。

首先,创建一个字典结构,前两个字段作为键和子键,并从第三个字段中收集值列表作为字典值:

set data {}
foreach v $val {
    lassign [split $v /] a b c
    if {![dict exists $data $a $b]} {
        dict set data $a $b {}
    }
    dict with data $a {
        lappend $b $c
        set b [lsort –integer $b]
    }
}

然后迭代这个字典结构,为键,子键,第一个和最后一个值的每个组合调用someproc命令。

dict for {a v} $data {
    dict for {b v} $v {
        someproc $a/$b/[lindex $v 0] - [lindex $v end]
    }
}

文档:dictforeachiflappendlassignlindexset,{{3 }}

相关问题