tcl lsearch в списке - PullRequest
       48

tcl lsearch в списке

6 голосов
/ 05 мая 2011

Список списков в Tcl.

set somelist {{aaa 1} {bbb 2} {ccc 1}}

Как найти элемент списка, первым элементом которого является "bbb"?

Я пробовал этот способ, но он не работает.

lsearch $somelist "{bbb *}"

Спасибо.

Ответы [ 5 ]

8 голосов
/ 05 мая 2011

Используйте -индекс , он предназначен именно для этого случая.Как указывает Раманман, когда у вас есть список, используйте процедуры списка.Задумывались ли вы о том, что произойдет, если у вас есть несколько совпадений?

В вашем случае я бы просто сделал следующее:

% lsearch -index 0 -all -inline $somelist bbb
{bbb 2}
% lsearch -index 0 -all $somelist "bbb"
1
% lsearch -index 0 -all $somelist "ccc"
2

Вы используете -индекс от 0 доукажите, что вас интересует первый индекс внешнего списка. -all возвращает все результаты.И вы можете использовать -inline , если вы просто хотите, чтобы значение элемента списка соответствовало, пропустите его, если вы просто хотите, чтобы индекс соответствовал элементу.

5 голосов
/ 05 мая 2011

Если вы просматриваете первый подсписок каждого члена списка, вам нужна опция -index:

set pos [lsearch -index 0 -exact $somelist "bbb"]

Опция -index 0 говорит механизму сравнения lsearch принятьпервый элемент каждого элемента (т. е. очень похож на lindex $item 0) перед выполнением любых других операций сравнения (-exact сравнение в моем примере).Вы даже можете предоставить список индексов для детализации в конкретный подсписок и т. Д.

( NB: Что lsearch делает не делаетвыполняет рекурсивный поиск по всем подспискам списка. Проблема в том, что формально невозможно узнать, когда вы дойдете до листьев.)


РЕДАКТИРОВАТЬ:
Если у вас старая версия Tcl, у вас может не быть опции -index.В этом случае вы используете ручную итерацию:

proc findElement {lst idx value} {
    set i 0
    foreach sublist $lst {
        if {[string equal [lindex $sublist $idx] $value]} {
            return $i
        }
        incr i
    }
    return -1
}
set pos [findElement $somelist 0 "bbb"]

(мне не нравится использовать глобальное сопоставление для такого рода вещей. Это также не очень хорошо работает, когда вы ищете элемент, который не 'первый или последний в списке.)

4 голосов
/ 05 мая 2011

В Tcl 8.5, но не в Tcl 8.4:

set somelist {{aaa 1} {bbb 2} {ccc 1}}
lsearch -index 0 $somelist bbb; # Returns either the index if found, or -1 if not

Флаги -index указывают, какой индекс подсписка искать: 0 ищет aaa, bbb, ... В то время как 1 ищетдля 1, 2, 1 ...

В Tcl 8.4 используйте команду keylget из пакета Tclx:

package require Tclx

set somelist {{aaa 1} {bbb 2} {ccc 1}}
set searchTerm "bbb"
if {[keylget somelist $searchTerm myvar]} {
    puts "Found instance of $searchTerm, value is: $myvar"
}

Команда keylget в этом синтаксисе возвращает 1, если найдено, 0, если найденоне.Значение рядом с bbb ​​(2) затем помещается в переменную myvar.Обратите внимание, что в команде keylget не должно быть знака доллара ($) перед somelist.

Update

Фактически флаг -index позволяет искать произвольную глубину, как показано в этом коде.:

package require Tcl 8.5 

# For each sub-list:
# - index 0 = the user's name
# - index 1 = a list of {home value}
# - index 2 = a list of {id value}
# - index 3 = a list of {shell value}
set users {
    {john {home /users/john} {id 501} {shell bash}}
    {alex {home /users/alex} {id 502} {shell csh}}
    {neil {home /users/neil} {id 503} {shell zsh}}
}   

# Search for user name == neil
set term neil
puts "Search for name=$term returns: [lsearch -index 0 $users $term]"; # 2

# Search for user with id = 502. That means we first looks at index
# 2 for {id value}, then index 1 for the value
set term 502
puts "Search for id=$term returns: [lsearch -index {2 1} $users $term]"; # 1

# Search for shell == sh (should return -1, not found)
set term sh
puts "Search for shell=$term returns: [lsearch -index {3 1} $users $term]"; # -1
2 голосов
/ 05 мая 2011

Используйте опцию "-index" [lsearch].

1 голос
/ 05 мая 2011

Если вы хотите искать его так, как вы пытаетесь, вы можете использовать опцию glob:

lsearch -glob $somelist "{bbb *}"

Если вы действительно списки списков, и вы ищете соответствие первому подспискус первым элементом bbb вы также можете сделать:

foreach sublist $somelist {   
  foreach {name value} $sublist {
    if {[string eq $name "bbb"]} {
      #do interesting stuff here
    }
  }
}

Подробности этого, конечно, будут зависеть от деталей вашего списка списков (если у вас есть только два элемента из вашего вложенного списка, илиесли бы это могло быть более глубоко вложенным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...