ลบองค์ประกอบหลายรายการออกจากรายการตามตำแหน่ง

ฉันต้องการลบองค์ประกอบบางอย่างออกจากรายการ จนถึงตอนนี้ฉันมีฟังก์ชั่นการลบ:

deleteElem :: Int -> [a] -> [a]
deleteElem _ [] = []
deleteElem x zs | x > 0 = take (x-1) zs ++ drop x zs
                | otherwise = zs

และฉันต้องการลบตัวอย่างสองตำแหน่งซึ่งจัดเก็บไว้ในรายการจากรายการองค์ประกอบ ดังนั้นมันใช้งานได้ดี:

map (deleteElem 2) [["hello", "whatever", "foo", "bar"], ["hello", "whatever", "foo", "bar"], ["hello", "whatever", "foo", "bar"], [hello", "whatever", "foo", "bar"]]

ฉันจะได้รับผลลัพธ์:

[["hello", "whatever", "bar"], ["hello", "whatever", "bar"], ["hello", "whatever", "bar"], [hello", "whatever", "bar"]]

แต่ตอนนี้อยากสมัคร deleteElem [2,3]


person Paktwis Homayun    schedule 25.09.2013    source แหล่งที่มา
comment
การแมปสองครั้งโดยมี DeleteElem เป็นตัวดำเนินการ แต่นั่นก็ไม่ได้ผลเช่นกัน   -  person Paktwis Homayun    schedule 25.09.2013


คำตอบ (2)


หากฉันตีความคำถามของคุณอย่างถูกต้อง คุณกำลังบอกว่าคุณต้องการวิธีใช้ฟังก์ชันของคุณกับรายการดัชนีแทนที่จะเป็นดัชนีเดียวในแต่ละครั้ง

วิธีที่ง่ายที่สุดที่ฉันสามารถทำได้คือสร้างฟังก์ชันอื่นที่เรียกว่า deleteElems แทน deleteElem (สังเกตส่วนท้าย s)

deleteElems จะเป็นประเภท [Int] -> [a] -> [a] และจะเรียกใช้ทุกดัชนี

หมายเหตุ: ดูการอัปเดตที่ด้านล่างสำหรับวิธีแก้ปัญหาที่ถูกต้อง (ฉันจะออกจากส่วนนี้ไว้ที่นี่เพื่อให้ผู้อื่นได้เรียนรู้จากความพยายามครั้งแรกของฉันในการแก้ปัญหาและสาเหตุที่ไม่ถูกต้อง)

นี่เป็นวิธีหนึ่งที่จะทำ:

deleteElems xs zs = foldr (\x z -> deleteElem x z) zs xs

ซึ่งสามารถย่อเป็น:

deleteElems xs zs = foldr deleteElem zs xs

Prelude> deleteElems [2,3] [1..10]
[1,4,5,6,7,8,9,10]

หรือจากตัวอย่างของคุณ:

Prelude> map (deleteElems [2,3]) [["hello", "whatever", "foo", "bar"], ["hello", "whatever", "foo", "bar"], ["hello", "whatever", "foo", "bar"], ["hello", "whatever", "foo", "bar"]]
[["hello","bar"],["hello","bar"],["hello","bar"],["hello","bar"]]

deleteElems ใช้ foldr เพื่อเรียก deleteElem ซ้ำๆ เพื่อลบดัชนีใน xs จาก zs หากต้องการคำอธิบายเชิงลึกเพิ่มเติมของ foldr โปรดดูที่ foldr ทำงานอย่างไร

อัปเดต:

ตามความคิดเห็น การใช้ deleteElems ข้างต้นนั้นไม่ถูกต้องจริง ๆ เพราะเมื่อได้รับรายการดัชนี เช่น [2,4,6] มันจะลบดัชนี 2 ก่อน ส่งคืนรายการใหม่ จากนั้นลบดัชนี 4 ในรายการ ใหม่ และ ส่งคืนรายการ ใหม่กว่า จากนั้นลบดัชนี 6 ในรายการ ใหม่กว่า กระบวนการนี้ไม่ใช่ สับเปลี่ยน หมายถึงการเปลี่ยนลำดับของดัชนี หรือการให้ deleteElems ดัชนี [6,4,2] จะไม่ทำสิ่งเดียวกัน

ฉันเป็นวิธีรับพฤติกรรมที่คาดหวัง (ลบดัชนีที่กำหนดออกจากรายการ ดั้งเดิม) โดยใช้ฟังก์ชัน intersect จาก Data.List:

deleteElems xs zs = foldr1 intersect $ map ($ zs) $ map deleteElem xs

deleteElems เวอร์ชันใหม่นี้ใช้ deleteElem โดยใช้แต่ละดัชนีใน xs โดยสร้างรายการ length xs จำนวนรายการของฟังก์ชัน deleteElem ที่รวบรวมไว้สำหรับแต่ละดัชนีเฉพาะ จากนั้น map ($ zs) จะใช้ฟังก์ชัน deleteElem ที่แกงกะหรี่แต่ละฟังก์ชันกับ zs โดยให้ผลลัพธ์เป็นรายการ โดยที่แต่ละรายการภายในจะใช้เพียง deleteElem กับหนึ่งในดัชนีและ zs สุดท้ายนี้ เราใช้ intersect จาก Data.List เพื่อค้นหารายการที่มีองค์ประกอบที่ถูกต้องทั้งหมดที่ถูกลบออก

นอกจากนี้ ฉันยังแนะนำให้ตรวจสอบ foldr ทำงานอย่างไร

person DJG    schedule 25.09.2013
comment
ลอง deleteElems [2, 4, 6] [1..10] == deleteElems [6, 4, 2] [1..10] มันเหมือนกันหรือเปล่า? มันควรจะเหมือนกันเหรอ? - person bheklilr; 25.09.2013
comment
คุณสามารถจัดเรียงรายการดัชนีจากมากไปน้อยได้ ปัญหาก็จะได้รับการแก้ไขเช่นกัน - person kaan; 25.09.2013

เรามานิยามการลบองค์ประกอบที่ตำแหน่ง i ว่าเป็นการแยกรายการที่ตำแหน่ง i จากนั้นจึงรวมรายการใหม่โดยไม่มีองค์ประกอบส่วนหัวของส่วนที่สองของรายการ นี่คือสิ่งที่คุณได้ดำเนินการอยู่แล้ว

ตอนนี้ การลบองค์ประกอบหลายรายการก็เหมือนกับการลบองค์ประกอบออกจากส่วนที่สองของรายการโดยใช้ขั้นตอนเดียวกัน หากเราสามารถระบุดัชนีที่เหลือโดยสัมพันธ์กับส่วนหัวของส่วนที่สองได้

สิ่งนี้เรียกร้องให้มีคำจำกัดความง่ายๆ ของ DeleteElems:

deleteElems is = del [i-p | (p:i:_) <- tails $ sort $ 0:is] where
  del [] xs = xs
  del is xs = (r++) $ concatMap tail ss where
     (r:rs,ts) = unzip $ zipWith splitAt is $ xs:ts
     ss = filter (not . null) $ rs ++ [last ts]

ที่นี่รายการความเข้าใจจะสร้างรายการดัชนีที่สัมพันธ์กับดัชนีก่อนหน้า จากนั้น del ใช้ zipWith splitAt เพื่อแยกรายการในตำแหน่งที่ระบุ หมายเหตุ xs:ts แสดงถึงรายการ "ส่วนที่สอง" ในการวนซ้ำทั้งหมด และ r:rs คือรายการ "ส่วนแรก" ในการวนซ้ำทั้งหมด เห็นได้ชัดว่า r เป็น "ส่วนแรก" แรกและรวมไว้ครบถ้วน ที่เหลือตัดด้วย tail จำเป็นต้องกรองรายการว่างในกรณีที่มีการระบุดัชนีเดียวกันมากกว่าหนึ่งครั้งในรายการดัชนี

person Sassa NF    schedule 25.09.2013