从tcl中的列表中搜索

时间:2013-11-20 02:24:46

标签: list tcl

我正在尝试搜索列表元素是否不等于0,如果它们不是,则返回指向单个元素或元素的指针并将其附加到列表中。

例如

list1有{a b c d e}

我使用一些api命令将这些元素的值提取到新列表

set list2 ""
foreach element $list1 {
    lappend list2 [api]    # Api is a procedure that queries a,b,c etc of list1 and then stores the value in list2.  
}

$> puts $list2
$> {0 0 4 0 1}       

这个list2可以包含列表中的任意数量的元素,并且订单不是固定的,所以我想开发一些适合任何事情的东西。例如,list2可以是{0 0 0}或{0 0 0 0 1 2 0}等。

现在回到我原来的问题,首先使用lsearch或者其他命令,我想检测是否有任何元素是0。如果不是,则将其附加到新列表。

set nonzero_list ""
# code below is wrong, I am trying to explain only what I a trying to achieve.
if {[lsearch $list2 0] != -1} {
    lappend nonzero_list ["element which is not zero, in our case it is 2nd and 4th element"]
}

最后我的输出应显示为:

$> puts $nonzero_list
{c e}     # Note: these are not actual individual elements of list2 but these are values of list1 to which they are associated to 

希望能够正确理解这个问题。

提前致谢。


/对于Hai Vu:下面更新的问题


你的proc“filterNonZero”工作正常。我的目标是将这些数字的值从此proc的输出附加到新列表。因此,在您提供的示例代码段中,列表2将获得正确的{1 2 3 5},但我想要一个属于这些元素的相应值的新列表list3。例如:

     set list0  {a b  c d e f g i} 

做一些处理并获得list2(我知道你在这里做什么,使用我的API) - >

    puts $list2 
    {0 1 2 0 3 0 0 5 0} 

然后使用您的proc获取列表2 - >

     set list2 [filterNonZero $list1] 
      puts $list2 
        { 1 2 3 5 }

- >现在做一些处理并获得最终结果列表3(我不知道如何做这部分) - >

       {b c e h}

2 个答案:

答案 0 :(得分:4)

过滤方式是:

set filteredList {}
foreach item $inputList {
    if {[api $item] != 0} {
        lappend filteredList $item,$val
    }
}

在Tcl 8.6中,我写了这个(因为continue跳过了收集身体的结果):

set filteredList [lmap item $inputList {
    if {[api $item] == 0} continue
    set item
}]

我总是假设您将项目作为参数传递给API。这是高度建议!

答案 1 :(得分:1)

如果我正确理解您的问题,您希望将列表作为输入并返回所有非零项目的列表。这是一种方法。

# Given list1 which contains any number of integers, we want to return a
# list of all items that is non-zero
set list1 {0 1 2 0 3 0 0 5 0}
set list2 {}
foreach item $list1 {
    if {$item != 0} {
        lappend list2 $item
    }
}

# At this point, list2 contains all the non-zero items from list1
puts "List1: $list1"
puts "List2: $list2"

输出:

List1: 0 1 2 0 3 0 0 5 0
List2: 1 2 3 5

您可以将其转换为proc(程序):

proc filterNonZero {theList} {
    set newList {}
    foreach item $theList {
        if {$item != 0} {
            lappend newList $item
        }
    }
    return $newList
}

set list1 {0 1 2 0 3 0 0 5 0}
set list2 [filterNonZero $list1]; # list2 = {1 2 3 5}

另一种方法是使用struct::list包来过滤掉你想要的东西:

package require struct::list
set list1 {0 1 2 0 3 0 0 5 0}
set list2 [struct::list filterfor item $list1 {$item != 0}]
puts "\nList2: $list2"

更新

让我看看我是否正确理解了这个问题:

list1  | a b c d e f g h i  
list2  | 0 1 2 0 3 0 0 5 0  
result |   b c   e     h  

如果这是你想要的,解决方案很简单:

# These are the input
set list1 {a b c d e f g h i}
set list2 {0 1 2 0 3 0 0 5 0}

set result {}
foreach item $list1 selector $list2 {
    if {$selector != 0} {
        lappend result $item
    }
}   

puts "result = $result"

讨论

  • 在这种情况下,list1是原始列表; list2是您通过致电[API]获得的。
  • 对于list2中的每个项目,如果该项目不为零,您希望在result
  • 中添加list1对应的项目
  • foreach循环执行此操作:它同时在两个列表中循环。
  • 您可能想要查看Donal Fellows'解决方案,他不需要创建list2,这可以节省一些步骤。