W danych wejściowych jest parzysta liczba elementów:
say elems <1 1 0 2 0 2 1 2 2 2 4 4 3 3>; # 14
Twój grep
blok zużywa za każdym razem dwa elementy:
{$^a eq $^b}
Więc jeśli dodasz lub usuniesz element, otrzymasz błąd, który pojawia się, gdy blok jest uruchamiany na pojedynczym elemencie pozostałym na końcu.
Istnieje wiele sposobów rozwiązania problemu.
Ale zapytałeś także o opcję pozwalającą na nakładanie się, więc na przykład, (2 2)
gdy 2 2 2
napotkasz sekwencję , otrzymujesz dwie listy podrzędne . I, w podobnym stylu, prawdopodobnie chcesz zobaczyć dwa dopasowania, a nie zero, z danymi wejściowymi takimi jak:
<1 2 2 3 3 4>
Dlatego skupię się na rozwiązaniach, które również zajmują się tymi problemami.
Pomimo zawężenia przestrzeni rozwiązań, aby poradzić sobie z dodatkowymi problemami, wciąż istnieje wiele sposobów funkcjonalnego wyrażania rozwiązań.
Jednym ze sposobów, który dodaje trochę więcej kodu na końcu twojego:
my @s = <1 1 0 2 0 2 1 2 2 2 4 4 3 3>;
say grep {$^a eq $^b}, @s .rotor( 2 => -1 ) .flat
.rotor
Metoda konwertuje listę do listy podlist, każdy o tej samej długości. Na przykład say <1 2 3 4> .rotor: 2
wyświetla ((1 2) (3 4))
. Jeśli argumentem długości jest para, kluczem jest długość, a wartość jest przesunięciem do rozpoczęcia następnej pary. Jeśli przesunięcie jest ujemne, nakłada się na siebie lista podrzędna. Tak say <1 2 3 4> .rotor: 2 => -1
wyświetla się ((1 2) (2 3) (3 4))
.
Że .flat
metoda „spłaszczony” jego invocant. Na przykład say ((1,2),(2,3),(3,4)) .flat
wyświetla (1 2 2 3 3 4)
.
Być może bardziej czytelnym sposobem na napisanie powyższego rozwiązania byłoby pominięcie flat
i użycie .[0]
oraz .[1]
indeksowanie do podlist, zwracanych przez rotor
:
say @s .rotor( 2 => -1 ) .grep: { .[0] eq .[1] }
Zobacz także komentarz Elizabeth Mattijsen na temat innej odmiany, która uogólnia dla dowolnej wielkości podlisty.
Jeśli potrzebujesz bardziej ogólnego wzorca kodowania, możesz napisać coś takiego:
say @s .pairs .map: { .value xx 2 if .key < @s - 1 and [eq] @s[.key,.key+1] }
.pairs
Sposób na liście zwraca listę parach, każda para odpowiadających każdej z tych elementów w ramach invocant listy. .key
Każdej pary jest indeksem element listy invocant; .value
jest wartość tego elementu.
.value xx 2
mógł zostać napisany .value, .value
. (Patrz xx
.)
@s - 1
to liczba elementów w @s
minus 1.
[eq]
W [eq] list
to ograniczenie .
Jeśli potrzebujesz dopasowania wzorca tekstowego, aby zdecydować, co stanowi ciągłe równe elementy, możesz przekonwertować listę wejściową na ciąg, dopasuj do tego za pomocą jednego z przysłówków dopasowujących, które generują listę dopasowań, a następnie odwzoruj z wynikowej listy dopasowań na żądany wynik. Aby dopasować z nakładaniem się (np. 2 2 2
Wyniki ((2 2) (2 2))
użycia :ov
:
say @s .Str .match( / (.) ' ' $0 /, :ov ) .map: { .[0].Str xx 2 }
2 2 2 2
, drukuje 3(2 2)
s, co jest zgodne z oczekiwaniami. Nigdy nie słyszałem o metodzierotor
Początkowo wymyśliłem tęsquish
metodę i sprawdziłem, czy ma ona cechy lub argumenty podobne,@s.squish(:length 2, :multiple_instances yes)
ale nie miała takich cech i nie nadawała się do tego zadania. W porównaniu zsquish
,rotor
wydaje się dość sprawny. W rzeczywistości może być nawet najodpowiedniejszy dla tego typu operacji.my $size = 2; say <1 1 0 2 0 2 1 2 2 2 4 4 3 3>.rotor( $size => -$size + 1).grep: { [eq] $_ }
# ((1 1) (2 2) (2 2) (4 4) (3 3)) Trzeba tylko dostosować$size
sekwencje dla różnych długości.rotor
, które dodałem, osłabiły lub wzmocniły moją odpowiedź.rotor
rozwiązaniasay @s.rotor(2=>-1).grep:{.[0]eq.[1]}
jest mile widziana, ponieważ jest zarówno krótsza (o 3 do 5 znaków w zależności od sposobu liczenia spacji) i nadal wygląda przyzwoicie. Uogólnione wersje bez tejrotor
metody są również mile widziane, ponieważ pokazują, jak niektóre dziwactwa lubiąxx
i:ov
są używane. Problem jest więc bardzo dobrze rozwiązany :)TIMTOWDI!
Oto iteracyjne podejście z użyciem
gather
/take
.źródło
take ($last, $_)
część jest dobrym przykładem użyciagather and take
duetu.