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 grepblok 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 2napotkasz 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
.rotorMetoda konwertuje listę do listy podlist, każdy o tej samej długości. Na przykład say <1 2 3 4> .rotor: 2wyś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 => -1wyświetla się ((1 2) (2 3) (3 4)).
Że .flatmetoda „spłaszczony” jego invocant. Na przykład say ((1,2),(2,3),(3,4)) .flatwyświetla (1 2 2 3 3 4).
Być może bardziej czytelnym sposobem na napisanie powyższego rozwiązania byłoby pominięcie flati 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] }
.pairsSposób na liście zwraca listę parach, każda para odpowiadających każdej z tych elementów w ramach invocant listy. .keyKażdej pary jest indeksem element listy invocant; .valuejest wartość tego elementu.
.value xx 2mógł zostać napisany .value, .value. (Patrz xx.)
@s - 1to liczba elementów w @sminus 1.
[eq]W [eq] listto 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 2Wyniki ((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 metodzierotorPoczątkowo wymyśliłem tęsquishmetodę 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,rotorwydaje się dość sprawny. W rzeczywistości może być nawet najodpowiedniejszy dla tego typu operacji.