Сравните 'n' количество списков в Tcl - PullRequest
1 голос
/ 07 марта 2019

У меня есть следующие списки:

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}

Я хочу сравнить все списки - по соответствующим индексам - и найти общие элементы и добавить эти общие элементы в новый список.Если я сравню вышеприведенные списки, я вижу, что 1 2 3 4 являются общими для всех списков и имеют одинаковый индекс, поэтому мой вывод должен быть:

{1 2 3 4}

Если нет общих элементов (даже при 0индекс) мой новый список будет пустым.

Сначала я начну с создания списка списков:

set l1 [list $w $x $y $z]

Затем я создаю вложенный цикл для сравнения списков и извлечения моегообщие элементы, я буду использовать список 'x' в качестве списка ссылок:

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
         }
    }

}

То, что я получаю:

1 2 3 4 5

Ответы [ 2 ]

2 голосов
/ 07 марта 2019

Аналогичная реализация, но с использованием массива для хранения уникальных элементов среза

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
1 голос
/ 07 марта 2019

Вы фактически сравниваете только список x со списком x, и фактический вывод из вашего кода выше (при условии, что список l2 изначально пуст) на самом деле:

1 2 3 4 5 8 9

Вы можетеспросите:

Почему он сравнивает список x со списком x?

Ваш внутренний цикл начинается с индекса 1 (set i 1), который является спискомx in l1.

Вы могли бы дополнительно спросить:

Почему другие списки не сравниваются?

После добавлениячто-то в l2, lindex $l2 $j для следующего списка никогда не будет пустым, поэтому внутренний цикл оборвется.


Итак, как это сделать?

Я бы, наверное,используйте что-то вроде этого:

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]
  }
}

Результат:

1 2 3 4

Вы можете сделать разрыв внутреннего цикла, если элементы не совпадают, поэтому он не будет повторяться без необходимости.

Или вместо подсчета количества совпадений вы можете проверить, не сломался ли внутренний цикл, например:

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]
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...