ค้นหาลำดับที่ต่อเนื่องกันขององค์ประกอบที่เท่ากันในรายการ Raku


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พบลำดับ และในหลอดเลือดดำที่คล้ายกันคุณอาจต้องการเห็นการแข่งขันสองรายการไม่ใช่ศูนย์โดยมีการป้อนข้อมูลเช่น:

<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วิธีการ "แบน" invocant ของมัน ยกตัวอย่างเช่นการแสดง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วิธีในรายการกลับรายการของคู่แต่ละคู่ที่สอดคล้องกับแต่ละองค์ประกอบในรายการ invocant ของตน .keyของแต่ละคู่เป็นดัชนีขององค์ประกอบในรายการ invocant นั้น .valueคุ้มค่าขององค์ประกอบ

.value xx 2สามารถเขียน.value, .valueได้ (ดูxx.)

@s - 1คือจำนวนขององค์ประกอบใน@sลบ 1

[eq]ใน[eq] listเป็นลดลง


หากคุณต้องการการจับคู่รูปแบบข้อความเพื่อตัดสินใจว่าองค์ประกอบใดที่มีองค์ประกอบเท่ากันอย่างต่อเนื่องคุณอาจแปลงรายการอินพุตให้เป็นสตริงให้จับคู่กับคำวิเศษณ์จับคู่ที่สร้างรายการการแข่งขันจากนั้นแมปจากรายการผลลัพธ์ของการจับคู่ที่คุณต้องการ ผลลัพธ์. เพื่อจับคู่กับการซ้อนทับ (เช่น2 2 2ผลลัพธ์ที่((2 2) (2 2))ใช้อยู่:ov:

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

มันใช้งานได้ค่อนข้างดี เมื่อฉันเพิ่ม 2 2 s เพื่อสร้างลำดับ2 2 2 2มันจะพิมพ์ 3 (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 โปรด LMK ถ้าคุณคิดว่าสองทางเลือกrotorที่ฉันเพิ่มเข้ามานั้นทำให้คำตอบของฉันอ่อนแอ
raiph

รุ่นที่ได้รับการปรับปรุงของrotorวิธีการแก้ปัญหาsay @s.rotor(2=>-1).grep:{.[0]eq.[1]}คือยินดีต้อนรับเพราะมันสั้นกว่า (โดย 3 ถึง 5 ตัวอักษรขึ้นอยู่กับการนับพื้นที่) และยังดูดี รุ่นทั่วไปที่ไม่มีrotorวิธีการก็ยินดีต้อนรับเช่นกันเพราะมันแสดงให้เห็นว่านิสัยใจคอบางอย่างเช่นxxและ:ovใช้อย่างไร ดังนั้นปัญหาได้รับการแก้ไขเป็นอย่างดี :)
Lars Malmsteen

5

TIMTOWDI!

นี่คือวิธีการใช้ซ้ำ/gathertake

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.