【问题标题】:Comparing two arrays, removing items that match比较两个数组,删除匹配的项目
【发布时间】:2012-06-14 03:26:53
【问题描述】:

我有两个数组,@names@employees,其中填充了代表名称的字符串。 @names 是二维的,持有对匿名数组的引用,但我们关心的数据的位置在 @names[i][0]。我想遍历@names 并找出哪些名字不在@employees 中。

起初我认为向后循环遍历@names,将其与@employees 进行比较并从@names 中删除任何匹配项都可以,但我遇到了一些错误。这是我所拥有的:

for my $i (reverse(0 .. $#names)) {
  foreach my $employee (@employees) {
    if ($names[$i][0] eq $employee) {  # line 67
      splice(@names, $i, 1);
    }
  }
}

我遇到了这个错误:

在 script.pl 第 67 行第 2 行的字符串 eq 中使用未初始化的值。

字符串都在数组中定义。所以我猜这是因为我在循环遍历数组时删除了数组中的元素,但我认为向后循环遍历数组可以防止这样的问题发生。

那么我的循环哪里出错了?此外,我一直在为这个循环而苦苦挣扎,这向我暗示我的整个思维过程出了点问题。有没有更好的方法来做到这一点?

【问题讨论】:

标签: arrays perl


【解决方案1】:

没有理由在这里显式循环。你想过滤名字:那是grep。您想检查成员资格:这也可以通过 grep 完成。

@names = grep {my $name = $$_[0]; not grep $_ eq $name, @employees} @names;

重复扫描内部数组并不是特别有效;可以通过提前预填充一个集合(实际上是一个哈希)来避免这种情况。

my %employees = map +($_ => 1), @employees;
@names = grep !$employees{$$_[0]}, @names;

【讨论】:

  • 直接使用值不是更好吗? @names = grep !$employees{$_}, @names;
  • @DanLittlejohn 根据 OP,@names 是一个二维数组,所以 $_ 仍然是一个列表引用。将其字符串化(哈希键会发生这种情况)没有用。
  • 这给出了一个Can't use string as an ARRAY ref while "strict refs" in use
【解决方案2】:

如果不提供代码,我会返回一个新的@names 列表。对于@names 中的每个名称,检查它是否在@employees 中,如果没有,则将其添加到您的新名称列表中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多