我怎样才能惯用地忽略未定义的数组元素(或者首先避免将它们分配给数组)?

时间:2017-08-23 16:18:08

标签: perl6 raku

如果为数组指定一个未定义的值,它将包含该未定义的值,如果您不想迭代未定义的值,则会使用循环变得复杂:

my @bar = 1, 2, Any;

for @bar -> $baz {
    put $baz;
}

这给出了以下输出,包括未定义值的警告:

1
2
Use of uninitialized value $baz of type Any in string context.
Methods .^name, .perl, .gist, or .say can be used to stringify it to something meaningful.
  in block  at for.p6 line 4

我知道我可以通过多种方式明确地处理这个问题,例如:

for @bar -> $baz {
    next unless $baz; # Skip this iteration
    put $baz;
}

for @bar.grep: *.defined {    # Just iterate over the defined values
    put $baz;
}

# Reassign @bar to only contain defined values
@bar.=grep(*.defined);
for @bar -> $baz {
    put $baz;
}

但是,是否有一种更惯用的方法可以避免@foo接收未定义的值或避免迭代未定义的值?

目前,在分配数组时,我将使用以下defined-flat函数来避免这些情况:

multi defined-flat (@array) {
    return @array.grep(*.defined).flat;
}

# Return single defined element (or empty list for single undefined value)
multi defined-flat ($element) {
    return $element // ();
}

6 个答案:

答案 0 :(得分:6)

您可以使用duckmap

                                                  Razao_social  Razao_social  \
business_id                                                                    

17                                             MULTIGRAIN S.A.     Sao Paulo   
17                                             MULTIGRAIN S.A.     Sao Paulo   
17                                             MULTIGRAIN S.A.     Sao Paulo   
17                                             MULTIGRAIN S.A.     Sao Paulo   
17                                             MULTIGRAIN S.A.     Sao Paulo   
17                                             MULTIGRAIN S.A.     Sao Paulo   
38           BRASILAGRO - COMPANHIA BRASILEIRA DE PROPRIEDA...     Sao Paulo   
38           BRASILAGRO - COMPANHIA BRASILEIRA DE PROPRIEDA...     Sao Paulo   
71                                    SECURITAS GARANTIAS S.A.     Sao Paulo   
71                                    SECURITAS GARANTIAS S.A.     Sao Paulo   
71                                    SECURITAS GARANTIAS S.A.     Sao Paulo   
71                                    SECURITAS GARANTIAS S.A.     Sao Paulo   
my @bar = 1, 2, Any;

@bar.duckmap: -> Mu:D $baz {
    put $baz;
}
duckmap -> Mu:D $baz {
    put $baz;
}, @bar;

答案 1 :(得分:6)

有时候,with语句也很方便,它既可以定义,也可以测试定义:

my @bar = 1, 2, Any;

for @bar -> $baz {
    put $_ with $baz
}

或者:

my @bar = 1, 2, Any;

for @bar {
    with $_ -> $baz {
        put $baz;
    }
}

答案 2 :(得分:3)

您可以grep定义项目

for @bar.grep(*.defined) -> $bar {
    say $bar;
}

当然,未定义的值是 Falsy ,所以如果你想要更短的东西(但不那么明确,IMO),你可以只为grep寻找 Truthy

for @bar.grep(&so) -> $bar {
    say $bar;
}

FWIW,只有第二个忽略给出的空列表:my @bar = [(1,2), (3,4), (), (7,8)];

答案 3 :(得分:3)

您也可以尝试使用map来解决问题:

my @a = [0, 1, 2, 3, Any].map({ $_ if $_.defined });

或者使用race启用多线程:

my @a = [0, 1, 2, 3, Any].race.map({ $_ if $_.defined });

>>.

my @a = [0, 1, 2, 3, Any]>>.&({ $_ if $_.defined });

我更喜欢最后一个:p

答案 4 :(得分:2)

如果你的真正问题是将一个未定义的元素分配给一个数组,那么添加defined-或//后跟一个空列表()Empty来创建一个空数组那些情况:

> my @bar =  Any;
[(Any)]
> my @bar =  Any  // ();
[]
> my @bar = (Any) // ();
[]
> my @bar =  Any  // Empty;
[]
my @bar   = (Any) // Empty;
[]

不会迭代空数组,因此单次迭代不会评估for @bar -> $baz {}

答案 5 :(得分:2)

我不确定这种惯用方法是什么,但是这个方法没有麻烦:

Perl6:

> my @a = [Any,1,2,3]
> grep { !($_.WHAT === Any) }, @a
> (1 2 3)

与Perl世界一样,有不止一种方法可以做到......