목록에서 동일한 요소의 연속 시퀀스 찾기


9

목록에서 동일한 요소 (예 : 길이 2)의 연속 시퀀스를 찾고 싶습니다.

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))

이 코드는 괜찮아 보이지만 시퀀스 후 2 개가 추가 2 2 2되거나 2 개가 제거되면 Too few positionals passed; expected 2 arguments but got 1어떻게 수정합니까? for루프 를 사용하지 않고 찾으려고 노력하고 있습니다 . 즉, 가능한 한 기능 코드를 사용하여 찾으려고합니다.

선택 사항 : 굵게 인쇄 된 섹션에서 :

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

다수의 서열 2 2이 보여진다. 보이는 횟수만큼 인쇄하는 방법은 무엇입니까? 처럼:

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

답변:


9

입력에 짝수 개의 요소가 있습니다.

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

귀하의 grep블록은 두 가지 요소마다 소모 :

{$^a eq $^b}

따라서 요소를 추가하거나 제거하면 마지막에 남은 단일 요소에서 블록을 실행할 때 오류가 발생합니다.


문제를 해결하는 방법에는 여러 가지가 있습니다.

그러나 겹치는 것을 허용하는 옵션에 대해서도 물었습니다. 예를 들어 (2 2)시퀀스 2 2 2가 발생 하면 두 개의 하위 목록이 표시됩니다 . 그리고 비슷한 맥락에서 아마도 다음과 같은 입력으로 0이 아닌 두 개의 일치 항목을보고 싶을 것입니다.

<1 2 2 3 3 4>

따라서 이러한 문제를 해결하는 솔루션에 중점을 두겠습니다.

추가 문제를 해결하기위한 솔루션 공간의 축소에도 불구하고 솔루션을 기능적으로 표현하는 방법은 여전히 ​​많습니다.


끝에 더 많은 코드를 추가하는 한 가지 방법은 다음과 같습니다.

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방법 은 목록을 각각 같은 길이의 하위 목록으로 변환합니다. 예를 say <1 2 3 4> .rotor: 2들어을 표시합니다 ((1 2) (3 4)). 길이 인수가 쌍인 경우 키는 길이이고 값은 다음 쌍을 시작하기위한 오프셋입니다. 오프셋이 음수이면 하위 목록이 겹칩니다. 따라서 say <1 2 3 4> .rotor: 2 => -1가 표시됩니다 ((1 2) (2 3) (3 4)).

.flat방법 은 그 주장자를 "평평하게한다". 예를 say ((1,2),(2,3),(3,4)) .flat들어을 표시합니다 (1 2 2 3 3 4).

위의 솔루션을 작성하는 더 읽기 쉬운 방법은 다음을 반환하여 하위 목록을 flat사용 .[0]하고 사용 .[1]하여 색인을 생성하는 것입니다 rotor.

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

하위 목록 크기를 일반화하는 다른 변형에 대해서는 Elizabeth Mattijsen의 의견도 참조하십시오.


보다 일반적인 코딩 패턴이 필요한 경우 다음과 같이 작성할 수 있습니다.

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

.pairs목록메소드 는 쌍 목록을 리턴합니다. 각 쌍은 호출자 목록의 각 요소에 해당합니다. .key각 쌍은 invocant리스트의 요소의 인덱스이고; 는 .value요소의 값이다.

.value xx 2쓸 수있었습니다 .value, .value. (참조 xx)

@s - 1@s빼기 1 의 요소 수입니다 .

[eq]의는 [eq] listA는 감소 .


연속적인 동일한 요소를 구성하는 요소를 결정하기 위해 텍스트 패턴 일치가 필요한 경우 입력 목록을 문자열로 변환하고 일치 목록을 생성하는 일치 부사 중 하나를 사용하여 일치시키는 다음 결과 일치 목록에서 원하는 결과로 매핑하십시오. 결과. 오버랩과 일치 시키려면 (예 : 사용중인 2 2 2결과)((2 2) (2 2)):ov

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

꽤 잘 작동합니다. 시퀀스를 만들기 위해 2 2를 추가하면 예상대로 2 2 2 23 초가 인쇄 (2 2)됩니다. rotor내가 처음에 방법을 생각해 낸 방법에 대해 들어 본 적이 없으며 squish기능이나 인수가 있는지 확인 @s.squish(:length 2, :multiple_instances yes)했지만 그러한 기능이 없었고 작업에 적합하지 않은지 확인했습니다. 에 비해 squish, rotor 상당히 맞는 것 같다. 실제로이 유형의 작업에 가장 적합한 것일 수도 있습니다.
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)) $size서로 다른 길이의 시퀀스에 대해서만 조정하면 됩니다.
Elizabeth Mattijsen

@LarsMalmsteen 님 안녕하세요. rotor내가 추가 한 두 가지 대안이 내 대답을 약화 시키거나 강화 했다고 생각되면 LMK를 참조하십시오 .
raiph

rotor솔루션 의 세련된 버전 즉 say @s.rotor(2=>-1).grep:{.[0]eq.[1]}, 공간이 계산되는 방식에 따라 3 ~ 5 자로 짧아지고 여전히 괜찮아 보이기 때문에 환영받습니다. 포함하지 않는 일반화 된 버전 rotor들이 같은 방법 몇 가지 단점을 표시하기 때문에 방법은 너무 환영 xx하고 :ov사용된다. 그래서 문제는 아주 잘 :) 해결
라스 Malmsteen

5

TIMTOWDI!

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))

응답 해주셔서 감사합니다. 그 자체로는 꽤 괜찮아 보입니다. 이 take ($last, $_)부분은 gather and take듀오 사용에 대한 적절한 예입니다 .
Lars Malmsteen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.