Neetu
Neetu

Reputation: 39

compare two lists in tcl and obtain list of only differences between lists

proc ListComp { List1 List2 } {
set DiffList {}
foreach Item $List1 {
  if { [ lsearch -exact $List2 $Item ] == -1 } {
     lappend DiffList $Item
  }
}
foreach Item $List2 {
  if { [ lsearch -exact $List1 $Item ] == -1 } {
     if { [ lsearch -exact $DiffList $Item ] == -1 } {
        lappend DiffList $Item
     }
  }
}
return $DiffList
}
set diff [Listcomp $list1 $list2]
puts diff

Input:

list1 {red, yellow, green, blue, orange}

list2 {red, green, blue, orange}

expected output: yellow

output received:

                 yellow green
                 green blue
                 blue orange
                 orange

The search and match should be either ways. if length of list1 > list2, the extra element in list1 should be printed. if length of list1 < list2, the omitted element in list1 should be printed

Upvotes: 1

Views: 3785

Answers (3)

Donal Fellows
Donal Fellows

Reputation: 137807

In general, each list could have elements that the other does not. The best approach is therefore to compute two result lists at the same time, being the elements present in one list that are absent in the other and vice versa. Then it's up to you to decide what to do with the information.

proc ComputeUniques {listA listB} {
    set A {}
    set B {}
    foreach a $listA {
        dict set A $a 0; # The 0 is just an arbitrary value
    }
    foreach b $listB {
        dict set B $b 0
        dict unset A $b
    }
    foreach a $listA {
        dict unset B $a
    }
    return [list [dict keys $A] [dict keys $B]]
}

Note that dict unset does nothing if the key is absent, which is convenient, and the results are in the order of occurrence of the input keys (strictly in the order of first occurrence, in the case of input lists that are not set-like).

Upvotes: 0

glenn jackman
glenn jackman

Reputation: 247250

Another approach is to use an array (or a dict):

set list1 {red yellow green blue orange}
set list2 {red green blue orange}

if {[llength $list1] > [llength $list2]} {
    set long $list1
    set short $list2
} else {
    set long $list2
    set short $list1
}

foreach elem $long {
    set diff($elem) 1
    # or: dict set diff $elem 1
}
foreach elem $short {
    unset -nocomplain diff($elem)
    # or: dict unset diff $elem
}

set difference [array names diff]
# or: set difference [dict keys $diff]

Upvotes: 1

Schelte Bron
Schelte Bron

Reputation: 4813

While your code (apart from typos) works, it can be done much simpler like this:

set diff [lmap n [concat $list1 $list2] {
    # Skip the elements that are in both lists
    if {$n in $list1 && $n in $list2} continue
    set n
}]

Upvotes: 2

Related Questions