2017-08-23 50 views
9

Jeśli przypiszesz nieokreślonej wartości do tablicy, to będzie zawierać tę wartość niezdefiniowana, co komplikuje za pomocą pętli, jeśli nie chcesz iteracyjne nad wartości niezdefiniowanych:Jak mogę idiomatycznie ignorować niezdefiniowane elementy tablicy (lub w ogóle unikać przypisywania ich do tablicy)?

my @bar = 1, 2, Any; 

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

To daje następujące dane wyjściowe, w tym ostrzeżenie dla wartości niezdefiniowanych:

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 

wiem, że mogę sobie z tym wyraźnie w wielu sposób, na przykład:

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

Ale czy nie istnieje bardziej idiomatyczny sposób na uniknięcie otrzymania niezdefiniowanych wartości przez @foo lub uniknięcie iteracji po niezdefiniowanych wartościach?


na razie, gdy przypisanie do tablicy, mam zamiar używać poniższego defined-flat funkcję, aby uniknąć takich sytuacji:

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 //(); 
} 
+1

"lub unikaj przypisywania ich do tablicy" - To naprawdę zależy od tego, jak budujesz tablicę.Najbardziej idiomatycznym rozwiązaniem byłoby prawdopodobnie wygenerowanie danych wejściowych dla tablicy w taki sposób, aby zawierały tylko zamierzone elementy i nie niezainicjowane "martwe" elementy. – smls

Odpowiedz

6

Można użyć 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; 
} 
+0

Wariant "map" na pewno należy pamiętać. Dzięki! –

6

także czasami przydatny jest oświadczenie with, której obie topicalizes i testy dla definedness:

my @bar = 1, 2, Any; 

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

czyli

my @bar = 1, 2, Any; 

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

Dzięki! 'with' jest bardzo użyteczne. Zacznę go używać. –

3

może po prostu grep dla określonych przedmiotów

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

Oczywiście, wartości nieokreślone są Falsy więc można po prostu grep dla Truthy te, jeśli chcesz coś krótszego (ale mniej wyraźny, IMO)

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

FWIW, tylko ten drugi ignoruje pustą listę biorąc pod uwagę: my @bar = [(1,2), (3,4),(), (7,8)];

+0

Interesujące. Drugi również ignoruje '0', ale gdybym nie oczekiwał' 0', to na pewno by się udało. –

+0

Dzięki. Nigdy nie zdawałem sobie sprawy, że mogę użyć '@ bar.grep (& so)'. Zastanawiam się, dlaczego '@ bar.grep (& defined)' nie działa. –

+0

Nie można użyć ['@ bar.grep (& zdefiniowane)' to błąd] (https://rt.perl.org/Public/Bug/Display.html?id=128905). –

3

można również spróbować użyć map do rozwiązania problemu:

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

Albo z race włączyć multi-wątków:

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

Albo >>.:

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

Wolę ostatni: P

+0

Interesujące. Czy '>>. &' Jest synonimem 'mapy', czy jest tam coś więcej? –

+1

Oto różnice: https://stackoverflow.com/a/38806794/8517446 –

2

Jeżeli prawdziwym problemem jest pojedynczym niezdefiniowany elementem coraz przypisany do tablicy, następnie dodaje się zdefiniowaną lub //, a następnie pustą listę () lub Empty, aby utworzyć pustą tablicę w następujących sytuacjach:

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

Pusta tablica nie zostanie poddana iteracji, a zatem for @bar -> $baz {} nie będzie rozpatrywana dla pojedynczej iteracji.

2

Nie jestem pewien, co jest idiomatycznych sposób, ale ten działa bez kłopotów:

Perl6: 

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

Jak zawsze ze światem Perl, istnieje więcej niż jeden sposób, aby robić rzeczy ...