[WJG] (16/Feb/06) A simple proc to compare the contents of two [list]s. It returns a list equal to the differences. #---------------- # compare list a with b #---------------- proc listcomp {a b} { set diff {} foreach i $a { if {[lsearch -exact $b $i]==-1} { lappend diff $i } } return $diff } catch {console show} set a {1 2 3 4 5 6} set b {2 4 6 8} puts "list a = \{$a\}\nlist b = \{$b\}\nThe difference between a and b is \{[listcomp $a $b]\}." ---- [male] - 2006-02-16: reading the title I thought about something like "'''string compare'''". So what's about this approach of a kind of list compare '''lcompare''': proc lcompare {list1 list2} { set length1 [llength $list1]; set length2 [llength $list2]; if {$length1 < $length2} { return [expr {double(-1)}]; } elseif {$length1 > $length2} { return [expr {double(1)}]; } if {[lindex $list1 0] eq $list1} { return [expr {double([string compare $list1 $list2])}]; } set result [expr {double(0)}]; foreach element1 $list1 element2 $list2 { set result [expr {$result + [lcompare $element1 $element2]}]; } return [expr {$result / $length1}]; } [WJG] (16/Feb/06) [male], what is this proc supposed to do? [male] - 2006-02-16: sorry I didn't explain it. '''lcompare''' returns a number between -1 and 1 to tell if the list1 is "lower" or "greater" than list2 - like in '''string compare'''. It is about comparing each atom of a list or sub lists with '''string compare'''. The results are summed and diveded by the count of compared atoms. I assumed this as one way to do this. Perhaps this is the wrong way! [WJG] (16/Feb/06) I fancied that the idea was to provide a simple decision. Running my clip above gives away the purpose. Its simply to compare one list with the other and then to return the differences. [jcw] - The way the original was written, it really is sort of a "minus" or "except" set operator. (Exercise for the reader: fix the error when this is given two identical lists) [AK] Feb 16, 2006: [Tcllib]'s [struct] module has a package [struct::set] with all kinds of set operators. The original '''listcomp''' is simply '''struct::set difference'''. [KBK] 2007-11-20 The "difference between two lists" is a trifle ambiguous. If the lists do indeed represent sets of items, then '''struct::set difference''' is what you want. If the lists are, say, lines from two versions of a file, and you want to find the difference the way the '''diff''' command does, then you're probably after '''struct::list longestCommonSubsequence''' (The '''struct::list lcsInvert''' call repackages the results of '''longestCommonSubsequence''' in a more convenient form.) See also [diff in Tcl]. ---- See also: [Additional list functions] ---- '''[applemcg] - 2012-02-11 17:00:52''' ''listcomp'' should be named something like '''lAlessB'''. what is the math term, "commutative"? this function removes "b" from "a". ---- [HaO] 2014-09-16: I often have the issue to quickly check two lists if they are equaln in the sense that: * Same list length * All elements equal As a list may not be in canonical form, a string compare is not suitable. In addition, I fear about shimmering. Up to now, I have solved this by a loop like on the page [Additional list functions]. [Aspect] has proposed the following on the chat: ======tcl [list {*}$l1] eq [list {*}$l2] ====== [RS] proposes this solution, if lists are representing sets (order does not matter): ======tcl proc leq {a b} {expr {[lsort $a] eq [lsort $b]}} % leq {1 2 3} {1 3 2} 1 % leq {1 2 3} {1 3 2 4} 0 ====== If order does matter (i.e. lists represent sequences), [lrange] makes a list canonical: ======tcl proc leq_s {a b} {expr {[lrange $a 0 end] eq [lrange $b 0 end]}} % leq_s {1 2 3} {1 2 3} 1 % leq_s {1 2 3} {1 3 2} 0 ====== ---- '''[tcl_hack] - 2015-08-14 13:52:07''' It seems to me that the listcomp proc will only show items in list "a" that are not in "b", but if there are items in "b" that are not in "a", they'd be missed. To see all the differences between both lists, I modified it like this: ====== 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 } ====== [ddavtyan] (3/June/17) Proc below will compare two lists and return lists with added/removed element values. ====== proc compare_lists {lst1 lst2 added_el_lst removed_el_lst} { upvar $added_el_lst added_lst upvar $removed_el_lst removed_lst array unset arr foreach n $lst1 { set arr($n) 0 } foreach n $lst2 { if {[info exists arr($n)]} { set arr($n) 1 } else { lappend added_lst $n } } foreach n [array names arr] { if {$arr($n) == 0} { lappend removed_lst $n } } } ====== <> String Processing