Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I idiomatically ignore undefined array elements (or avoid assigning them to an array in the first place)?

Tags:

raku

If you assign an undefined value to an array, it will contain that undefined value, which complicates using loops if you don't want to iterate over undefined values:

my @bar = 1, 2, Any;

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

This gives the following output, including a warning for the undefined values:

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

I know that I can deal with this explicitly in a number of way, for example:

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;
}

But, isn't there a more idiomatic way to avoid @foo receiving undefined values or to avoid iterating over undefined values?


For the time being, when assigning to an array, I'm going to be using the following defined-flat function to avoid these situations:

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 // ();
}
like image 934
Christopher Bottoms Avatar asked Aug 23 '17 16:08

Christopher Bottoms


3 Answers

You also can try to use map to solve the problem:

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

Or with race to enable multi-threads:

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

Or >>.:

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

I prefer the last one :p

like image 99
Sun Wenjie Avatar answered Sep 28 '22 17:09

Sun Wenjie


You could use duckmap

my @bar = 1, 2, Any;

@bar.duckmap: -> Mu:D $baz {
    put $baz;
}
duckmap -> Mu:D $baz {
    put $baz;
}, @bar;
# the “:” makes this a method call
duckmap @bar: -> Mu:D $baz {
    put $baz;
}
like image 6
Brad Gilbert Avatar answered Nov 04 '22 13:11

Brad Gilbert


Also sometimes handy is the with statement, which both topicalizes and tests for definedness:

my @bar = 1, 2, Any;

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

Or:

my @bar = 1, 2, Any;

for @bar {
    with $_ -> $baz {
        put $baz;
    }
}
like image 6
dwarring Avatar answered Nov 04 '22 12:11

dwarring