【问题标题】:Compare 'n' number of lists in Tcl比较 Tcl 中的“n”个列表
【发布时间】:2019-03-07 22:04:21
【问题描述】:

我有以下列表:

set w {1 2 3 4 5 6 7}
set x {1 2 3 4 5 8 9}
set y {1 2 3 4 0 9 1}
set z {1 2 3 4 5 6 7}

我想比较所有列表 - w.r.t 对应的索引 - 并找出共同元素并将这些共同元素附加到新列表中。如果我比较上面的列表,我发现1 2 3 4 在所有列表中都很常见并且具有相同的索引,所以我的输出应该是:

{1 2 3 4}

如果没有公共元素(即使在第 0 个索引处),我的新列表将为空。

我首先创建一个列表列表:

set l1 [list $w $x $y $z]

然后我创建一个嵌套循环来比较列表并提取我的共同元素,我将使用列表'x'作为我的参考列表:

for {set j 0} {$j < [llength $x]} {incr j} {
    for {set i 1} {$i < [llength $l1]} {incr i} {

         set a [lindex [lindex $l1 $i] $j]

         if {$a == [lindex $x $j] && [lindex $l2 $j] == {}} {
                lappend l2 $a
         } else {
           break
         }
    }

}

我得到的是:

1 2 3 4 5

【问题讨论】:

    标签: tcl


    【解决方案1】:

    类似的实现,但使用数组来存储切片的唯一元素

    set lists [list $w $x $y $z]
    set common [list]
    
    for {set i 0} {$i < [llength $w]} {incr i} {
        array unset elements
        foreach list $lists {
            set elements([lindex $list $i]) dummyvalue
        }
        set unique [array names elements]
        if {[llength $unique] == 1} {
            lappend common $unique
        }
    }
    
    puts $common  ;# => 1 2 3 4
    

    【讨论】:

      【解决方案2】:

      您实际上只是将列表x 与列表x 进行比较,而上面代码的实际输出(假设列表l2 最初为空)实际上是:

      1 2 3 4 5 8 9
      

      你可能会问:

      为什么要将列表 x 与列表 x 进行比较?

      您的内部循环从索引 1 (set i 1) 开始,即 l1 中的列表 x

      你可能会进一步问:

      为什么不比较其他列表?

      一旦你向l2 附加了一些东西,lindex $l2 $j 的下一个列表永远不会为空,因此内部循环将中断。


      那么,该怎么做呢?

      我可能会使用这样的东西:

      set w {1 2 3 4 5 6 7}
      set x {1 2 3 4 5 8 9}
      set y {1 2 3 4 0 9 1}
      set z {1 2 3 4 5 6 7}
      
      set l1 [list $w $x $y $z]
      set l2 [list]
      
      set num [llength $x]
      
      for {set i 0} {$i < $num} {incr i} {
        # This variable will tell us how many matched. 0 indicating none.
        set same 0
      
        for {set j 0} {$j < [llength $l1]} {incr j} {
          # lindex accepts multiple indices, see the manual
          # using x as reference, if the current list's ith element is the same as x's ith element...
          if {[lindex $l1 $j $i] == [lindex $x $i]} {
            incr same
          }
        }
      
        # if same reached 4, means 4 matched
        if {$same == 4} {
          lappend l2 [lindex $x $i]
        }
      }
      

      结果:

      1 2 3 4
      

      如果元素不匹配,您可以中断内部循环,因此它不会不必要地循环。

      或者,您可以检查内部循环是否中断,而不是计算匹配数:

      for {set i 0} {$i < $num} {incr i} {
        set broke 0
      
        for {set j 0} {$j < [llength $l1]} {incr j} {
          if {[lindex $l1 $j $i] != [lindex $x $i]} {
            set broke 1
            break
          }
        }
      
        # if it did not break, then we know all matched
        if {$broke == 0} {
          lappend l2 [lindex $x $i]
        }
      }
      

      【讨论】:

      • 谢谢,这行得通!我没有注意到与同一个列表进行比较的错误,我最初的目标是避免它并保留l1(或)w 中的第一个列表作为我的参考,并在比较过程中跳过它。另外,我添加&amp;&amp; [lindex $l2 $j] == {} 的原因是因为我得到了1 1 1 2 2 2 3 3 3 4 4 4 5。我仍然有点不确定为什么当a 变为5 时我的循环没有终止。
      • 没关系,我明白了。即使元素与第二个列表中的元素匹配,我的循环也只会附加元素。如果在其他 n-1 个列表中发现不等式,我没有添加代码来删除已附加的数字。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-06-06
      • 1970-01-01
      • 1970-01-01
      • 2021-11-16
      • 2018-03-19
      • 1970-01-01
      • 2011-06-19
      相关资源
      最近更新 更多