[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 } <> String Processing