【问题标题】:Comparing two lists and returning the difference比较两个列表并返回差异
【发布时间】:2014-02-26 18:33:43
【问题描述】:

我有两个列表,我匹配它们并打印任何差异。这两个列表是 FPGA 站内的电缆连接。我需要确保:

  1. $list1上的所有连接都存在于$list2上,如果不存在,它应该将错误保存在另一个列表中

  2. $list2 上的所有连接都存在于 $list1 上,所以我没有得到任何“错误”连接。

  3. 任何一个列表中都不存在的连接应保存到另一个变量中。

列表格式如下:

{{A.B2} {B.B3}} 

$list2 等价物可能是:

{{B.B3} {A.B2}}

^ 即使交换了连接,它仍然有效!我将这两个都保存在循环内的不同变量中以执行此操作:

if {
    $physical == "$project" && $physical2 == "$project2"
    || $physical == "$project2" && $physical2 == "$project"
} then {
    lappend verified "$project ($project2) VERIFIED\n"
    #incr cablecounter
    set h 0
} elseif {
    $physical == "$project" && $physical2 != "$project2"
    || $physical != "$project" && $physical2 == "project2"
    || $physical == "$project2" && $physical2 != "project"
    || $physical != "$project2" && $physical2 == "project"
} then {
    lappend nonverified "$project to $project2 NOT connected. Please check $physical and $physical2\n"
} else {
    set g [expr $g - 1]
    incr h
    #puts "\n [llength configuredConnections]"      
    if {
        $h > [llength $configuredConnections] && $project != "$physical" && $project2 != "$physical2"
        || $h > [llength $configuredConnections] && $project != "physical2" && $project2 != "$physical"
    } {
        lappend nonverified "$project to $project2 wrong connection found. Please remove.\n"
        set h 0; incr g
    }   
}

这给了我所有错误的连接等,但不是告诉我$list1 上的元素在$list2 上不存在,而是将其存储到$nonverified,并且列表是“错误连接”而不是将其列为“未连接”。

我是 TCL 新手,不知道该怎么办!

编辑:$project$project2$list1 中的两个元素,$physical $physical2$list2 中的元素。

我使用的是 Tcl 8.4

【问题讨论】:

  • 您可能希望使用括号 () 对您的条件进行分组,以便它更具可读性,并且您可以确定首先要评估的内容。

标签: list variables loops tcl


【解决方案1】:

ldiff 命令可以帮助您(编辑:我用 Tcl 8.4-workable 替换了 Tcl 8.6 实现(假设您使用下面的 lmap 替换)之一):

proc ldiff {a b} {
    lmap elem $a {
        expr {[lsearch -exact $b $elem] > -1 ? [continue] : $elem}
    }
}

调用

ldiff $list1 $list2

为您提供list1 中没有出现在list2 中的所有元素,反之亦然。

两个列表中都不存在的项目可能应该位于名为 list0 的列表中,您可以通过调用找到它们

ldiff [ldiff $list0 $list1] $list2

为 Tcl 8.4 用户快速替换 lmap

proc lmap {varname listval body} {
    upvar 1 $varname var
    set temp [list]
    foreach var $listval {
        lappend temp [uplevel 1 $body]
    }
    set temp
}

它不允许多个 varname-listval 对,但 ldiff 不需要。

这应该可以替代 Tcl 8.4 上的完整 lmap 命令,除非在使用 8.6 时仍然存在未出现的问题:

proc lmap args {
    set body [lindex $args end]
    set args [lrange $args 0 end-1]
    set n 0
    set pairs [list]
    foreach {varname listval} $args {
        upvar 1 $varname var$n
        lappend pairs var$n $listval
        incr n
    }
    set temp [list]
    eval foreach $pairs [list {
        lappend temp [uplevel 1 $body]
    }]
    set temp
}

在这种情况下,我仍然推荐第一个替换建议:它不会出错。

【讨论】:

  • 我使用的是 Tcl 8.4,没有 lmap
  • @user3201970:你现在拥有它;)
【解决方案2】:

这个过程将返回两个列表之间的交集和差异。对于 Tcl 8.4,可以这样称呼它

foreach {intersection not_in_list2 not_in_list1} \
        [intersect3 $list1 $list2] \
        break

if {[llength $not_in_list2] > 0} {
    puts "NOT All the connections on the list1 exist on list2"
    puts $not_in_list2
}

if {[llength $not_in_list1] > 0} {
    puts "NOT All the connections on the list2 exist on list1"
    puts $not_in_list1
}

(Tcl 8.5 及更高版本,你会

lassign [intersect3 $list1 $list2] intersection not_in_list2 not_in_list1

)

intersect3 过程是:

#
# intersect3 - perform the intersecting of two lists, returning a list
# containing three lists.  The first list is everything in the first
# list that wasn't in the second, the second list contains the intersection
# of the two lists, the third list contains everything in the second list
# that wasn't in the first.
#

proc intersect3 {list1 list2} {
    array set la1 {}
    array set lai {}
    array set la2 {}
    foreach v $list1 {
        set la1($v) {}
    }
    foreach v $list2 {
        set la2($v) {}
    }
    foreach elem [concat $list1 $list2] {
        if {[info exists la1($elem)] && [info exists la2($elem)]} {
            unset la1($elem)
            unset la2($elem)
            set lai($elem) {}
        }
    }
    list [lsort [array names la1]] [lsort [array names lai]] \
         [lsort [array names la2]]
}

我相信我是几年前从 TclX 那里偷来的。你可以(应该?)使用tcllib:

package require struct::set
set l1 {a b c d e f g}
set l2 {c d e f g h i}
puts [struct::set intersect3 $l1 $l2]
{c d e f g} {a b} {h i}

【讨论】:

  • 习惯上最好使用lassign,然后引用foreach 方式作为8.4 及之前版本的解决方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-08
  • 2021-08-30
  • 1970-01-01
  • 2013-04-25
  • 1970-01-01
  • 2023-03-03
  • 1970-01-01
相关资源
最近更新 更多