Tìm chuỗi liên tục của các phần tử bằng nhau trong danh sách Raku


9

Tôi muốn tìm các chuỗi liền kề của các phần tử bằng nhau (ví dụ: độ dài 2) trong danh sách

my @s = <1 1 0 2 0 2 1 2 2 2 4 4 3 3>;
say grep {$^a eq $^b}, @s;

# ==> ((1 1) (2 2) (4 4) (3 3))

Mã này có vẻ ổn nhưng khi thêm một 2 nữa sau chuỗi 2 2 2hoặc khi một 2 bị xóa khỏi nó, nó nói Too few positionals passed; expected 2 arguments but got 1Làm thế nào để sửa nó? Xin lưu ý rằng tôi đang cố gắng tìm chúng mà không sử dụng forvòng lặp, tức là tôi đang cố gắng tìm chúng bằng mã chức năng càng nhiều càng tốt.

Tùy chọn: Trong phần in đậm:

<1 1 0 2 0 2 1 2 2 2 4 4 3 3>

nhiều trình tự 2 2được nhìn thấy. Làm thế nào để in cho họ số lần họ được nhìn thấy? Giống:

((1 1) (2 2) (2 2) (4 4) (3 3))

Câu trả lời:


9

Có một số phần tử chẵn trong đầu vào của bạn:

say elems <1 1 0 2 0 2 1 2 2 2 4 4 3 3>; # 14

grepKhối của bạn tiêu thụ hai yếu tố mỗi lần:

{$^a eq $^b}

Vì vậy, nếu bạn thêm hoặc xóa một phần tử, bạn sẽ gặp phải lỗi khi khối được chạy trên phần tử còn lại ở cuối.


Có nhiều cách để giải quyết vấn đề của bạn.

Nhưng bạn cũng đã hỏi về tùy chọn cho phép chồng lấp, vì vậy, ví dụ, bạn nhận được hai (2 2)danh sách phụ khi 2 2 2gặp phải chuỗi . Và, trong một tĩnh mạch tương tự, có lẽ bạn muốn xem hai trận đấu, không phải bằng 0, với đầu vào như:

<1 2 2 3 3 4>

Vì vậy, tôi cũng sẽ tập trung vào các giải pháp giải quyết những vấn đề đó.

Mặc dù thu hẹp không gian giải pháp để giải quyết các vấn đề bổ sung, vẫn có nhiều cách để thể hiện giải pháp theo chức năng.


Một cách chỉ thêm một chút mã vào cuối của bạn:

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

Các .rotorphương pháp chuyển đổi một danh sách vào một danh sách các tiểu danh sách, mỗi chiều dài tương tự. Ví dụ, say <1 2 3 4> .rotor: 2hiển thị ((1 2) (3 4)). Nếu đối số độ dài là một cặp, thì khóa là độ dài và giá trị là phần bù để bắt đầu cặp tiếp theo. Nếu phần bù là âm, bạn sẽ có danh sách phụ trùng lặp. Do đó say <1 2 3 4> .rotor: 2 => -1hiển thị ((1 2) (2 3) (3 4)).

Các .flatphương pháp "flattens" invocant của nó. Ví dụ, say ((1,2),(2,3),(3,4)) .flathiển thị (1 2 2 3 3 4).

Một cách có lẽ dễ đọc hơn để viết giải pháp trên sẽ là bỏ qua flatvà sử dụng .[0].[1]lập chỉ mục vào các danh sách phụ được trả về bởi rotor:

say @s .rotor( 2 => -1 ) .grep: { .[0] eq .[1] }

Xem thêm bình luận của Elizabeth Mattijsen cho một biến thể khác khái quát cho mọi kích thước danh sách phụ.


Nếu bạn cần một mẫu mã hóa tổng quát hơn, bạn có thể viết một cái gì đó như:

say @s .pairs .map: { .value xx 2 if .key < @s - 1 and [eq] @s[.key,.key+1] }

Các .pairsphương pháp trên một danh sách trả về một danh sách các cặp, mỗi cặp tương ứng với mỗi người trong số các yếu tố trong danh sách invocant của nó. Các .keycủa mỗi cặp là chỉ số của phần tử trong danh sách invocant; những .valuelà giá trị của nguyên tố này.

.value xx 2có thể đã được viết .value, .value. (Xem xx.)

@s - 1là số phần tử trong @sâm 1.

Các [eq]trong [eq] listlà một giảm .


Nếu bạn cần khớp mẫu văn bản để quyết định yếu tố nào tạo thành các phần tử bằng nhau liền kề, bạn có thể chuyển đổi danh sách đầu vào thành chuỗi, khớp với đó bằng một trong các trạng từ khớp tạo ra danh sách khớp, sau đó ánh xạ từ danh sách kết quả khớp với mong muốn của bạn kết quả. Để khớp với các lớp phủ (ví dụ: 2 2 2kết quả được ((2 2) (2 2))sử dụng :ov:

say @s .Str .match( / (.) ' ' $0 /, :ov ) .map: { .[0].Str xx 2 }

Nó hoạt động khá tốt. Khi tôi thêm 2 2 giây để tạo chuỗi, 2 2 2 2nó sẽ in 3 (2 2)giây như mong đợi. Chưa bao giờ nghe về phương pháp rotorban đầu tôi đã đưa ra squishphương pháp và kiểm tra xem nó có các tính năng hoặc đối số như thế nào không @s.squish(:length 2, :multiple_instances yes)nhưng nó không có các tính năng như vậy và nó không phù hợp với nhiệm vụ. So với squish, rotor có vẻ khá phù hợp. Trên thực tế, nó thậm chí có thể là mạnh nhất cho loại hình hoạt động này.
Lars Malmsteen

3
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)) Bạn chỉ cần điều chỉnh các $sizeđộ dài khác nhau của chuỗi.
Elizabeth Mattijsen

Xin chào lần nữa @LarsMalmsteen. Vui lòng LMK nếu bạn nghĩ rằng hai lựa chọn thay thế rotormà tôi đã thêm đã làm suy yếu hoặc củng cố câu trả lời của tôi.
raiph

Phiên bản tinh chỉnh của rotorgiải pháp tức say @s.rotor(2=>-1).grep:{.[0]eq.[1]}là được hoan nghênh vì cả hai đều ngắn hơn (từ 3 đến 5 ký tự tùy thuộc vào cách tính khoảng trắng) và trông vẫn ổn. Các phiên bản tổng quát mà không có rotorphương pháp cũng được hoan nghênh vì chúng cho thấy một số quirks thích xx:ovđược sử dụng như thế nào. Vì vậy, vấn đề được giải quyết rất tốt :)
Lars Malmsteen

5

THỜI GIAN!

Đây là một cách tiếp cận lặp lại bằng cách sử dụng gather/ take.

say gather for <1 1 0 2 0 2 1 2 2 2 4 4 3 3> { 
    state $last = ''; 
    take ($last, $_) if $last == $_; 
    $last = $_; 
};

# ((1 1) (2 2) (2 2) (4 4) (3 3))

Cảm ơn bạn đã trả lời. Điều đó có vẻ khá tốt theo đúng nghĩa của nó. Phần take ($last, $_)này là một ví dụ điển hình về việc sử dụng gather and takebộ đôi này.
Lars Malmsteen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.