Reputation: 61
I have the following lists:
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}
I want to compare all the lists - w.r.t corresponding indices - and find out the common elements and append those common elements to a new list. If I compare the above lists, I see that 1 2 3 4
are common across all the lists and have the same index, so my output should be:
{1 2 3 4}
If there are no common elements(even at 0'th index) my new list will be empty.
I first start off by creating a list of lists:
set l1 [list $w $x $y $z]
Then I create a nested loop to compare the lists and extract my common elements, I will be using list 'x' as my reference list:
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
}
}
}
What I'm getting is:
1 2 3 4 5
Upvotes: 1
Views: 430
Reputation: 247260
Similar implementation, but using an array to store the unique elements of the slice
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
Upvotes: 2
Reputation: 71598
You are effectively only comparing list x
against list x
, and the actual output from your code above (assuming list l2
is initially empty) is actually:
1 2 3 4 5 8 9
You might ask:
Why is it comparing list
x
against listx
?
Your inner loop starts at index 1 (set i 1
), which is list x
in l1
.
You might further ask:
Why are the other lists not being compared?
Once you have appended something to l2
, lindex $l2 $j
for the next list will never be empty, so the inner loop will break.
So, how to do it?
I would probably use something like this:
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]
}
}
Result:
1 2 3 4
You could make the inner loop break if the elements do not match, so it won't loop unnecessarily.
Or instead of counting the number of matches, you could check if the inner loop broke with something like:
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]
}
}
Upvotes: 1