【问题标题】:How can I grep through an array, while filtering out matches?如何在过滤出匹配项的同时通过数组进行 grep?
【发布时间】:2011-07-16 11:20:21
【问题描述】:

有没有一种快速简便的方法来通过数组查找满足某些测试的元素从原始数组中删除这些元素?

例如我想要

@a = (1, 7, 6, 3, 8, 4);
@b = grep_filter { $_ > 5 } @a;

# now @b = (7, 6, 8)
# and @a = (1, 3, 4)

换句话说,我想将一个数组拆分为两个数组:匹配某个条件的数组和不匹配某个条件的数组。

【问题讨论】:

  • 为什么?从 @a (foreach (@a) { if( $_ > 5) { push @b, $_; } else { push @c, $_; } }) 创建 2 个数组很简单且易于阅读,为什么需要“部分就地”执行此操作?

标签: arrays perl


【解决方案1】:

了解你的库,老兄。

use List::MoreUtils qw(part);
part { $_>5 } (1, 7, 6, 3, 8, 4)

返回

(
    [1, 3, 4],
    [7, 6, 8],
)

【讨论】:

  • 不错,正是我想要的。
【解决方案2】:
my @a = (1, 7, 6, 3, 8, 4);
my (@b, @c);    

push @{ $_ > 5 ? \@b : \@c }, $_ for @a;

【讨论】:

  • +1 因为它是一个很好的解决方案,不需要任何外部库。
【解决方案3】:

使用库很好,但为了完整起见,这里是问题中指定的函数:

sub grep_filter (&\@) {
    my ($code, $src) = @_;
    my ($i, @ret) = 0;
    local *_;
    while ($i < @$src) {
        *_ = \$$src[$i];
        &$code
            ? push @ret, splice @$src, $i, 1
            : $i++
    }
    @ret
}

my @a = (1, 7, 6, 3, 8, 4);
my @b = grep_filter {$_ > 5} @a;

say "@a"; # 1 3 4
say "@b"; # 7 6 8

【讨论】:

    【解决方案4】:

    这是你想要的吗?

    @a = (1, 7, 6, 3, 8, 4);
    @b = grep_filter { $_ > 5 } @a;
    @a = grep_filter { $_ < 5 } @a;
    

    在你的条件被否定的情况下再做一次 grep。

    【讨论】:

    • &lt; 不是&gt; 的严格否定。
    • @Alnitak - 你说得对,我没有提到这一点,但我输入了&lt; 而不是&lt;=,以便代码按预期工作
    • @Tudor:为什么逻辑错误会使代码按预期工作,而不是正确的
    • @pavel 在我看来只是因为 5 实际上不在列表中。
    • 如果列表中有 5 个(包含奇数个元素),如何将其拆分为 2 个相同长度的列表?
    猜你喜欢
    • 1970-01-01
    • 2022-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多