Haskell: แบ่งองค์ประกอบคู่และคี่ออกเป็นทูเพิล

ฉันไม่สามารถใช้ฟังก์ชันลำดับสูงได้ ฉันไม่เห็นว่าจะต้องทำอย่างไร ฉันยังใหม่กับ haskell มาก มันจะต้องมีการเรียกซ้ำด้วย

split :: [Int] -> ([Int],[Int])
split xs = 

ฉันได้รับสิ่งนี้เพื่อเริ่มต้นด้วย ฉันไม่รู้ด้วยซ้ำว่าจะเริ่มต้นปัญหานี้จากตรงไหน

ตัวอย่าง:

split []
([],[])

split [1]
([1],[])

split [1,2,3,4,5,6,7,8,9,10]
([1,3,5,7,9],[2,4,6,8,10])

ความช่วยเหลือใด ๆ ที่จะได้รับการชื่นชมมาก

แก้ไข: ตำแหน่งคู่และคี่

So

แยก [3,6,8,9,10] จะเป็น ([3,8,10],[6,9])

โอเค ฉันคิดเรื่องนี้ขึ้นมา มันไม่สวย แต่ดูเหมือนว่าจะทำงานได้ดี

split :: [Int] -> ([Int],[Int])
split [] = ([],[])
split [xs] = ([xs],[])
split xs = (oddlist xs, evenlist xs)

oddlist :: [Int] -> ([Int])
oddlist xs | length xs <= 2 = [head(xs)]
           | otherwise = [head(xs)] ++ oddlist(tail(tail(xs)))

evenlist :: [Int] -> ([Int])
evenlist xs | length xs <= 3 = [head(tail(xs))]
            | otherwise = [head(tail(xs))] ++ evenlist(tail(tail(xs)))

person Matt    schedule 14.09.2010    source แหล่งที่มา
comment
ตัวอย่างของคุณค่อนข้างคลุมเครือ คุณหมายถึงองค์ประกอบที่ตำแหน่งคู่และคี่ หรือจำนวนเต็มที่เป็นคู่หรือคี่? ตัวอย่างที่ดีกว่าอาจเป็น: split [1,3,2,5,8] ~› ([1,3,5], [2,8])   -  person Tom Lokhorst    schedule 14.09.2010
comment
โอ้ ใช่แล้ว ขออภัย องค์ประกอบที่ตำแหน่งคู่และคี่   -  person Matt    schedule 14.09.2010
comment
@ทอม เฮ้ ขอบคุณ ไม่ได้สังเกตว่า.   -  person Matt    schedule 14.09.2010


คำตอบ (5)


หากคุณผ่อนปรนข้อจำกัด "ไม่มีฟังก์ชันลำดับที่สูงกว่า" คุณสามารถทำได้ดังนี้:

split :: [a] -> ([a],[a])
split = foldr (\x ~(y2,y1) -> (x:y1, y2)) ([],[])

โปรดทราบว่า ~ ทำให้การจับคู่รูปแบบเป็นแบบ Lazy ดังนั้น split จึงสามารถสร้างผลลัพธ์ตามความต้องการ แทนที่จะต้องตรวจสอบรายการทั้งหมดก่อน

คุณสามารถกำหนดข้อจำกัดใหม่ได้โดยขยาย foldr:

split :: [a] -> ([a],[a])
split [] = ([],[])
split (x : xs) = (x : y1, y2)
  where
    (y2, y1) = split xs
person BarbedWire    schedule 17.03.2016
comment
ฉันแก้ไขผลลัพธ์ที่สลับแล้ว และทำให้สิ่งต่าง ๆ เป็นไปตามที่คาดไว้ - person dfeuer; 17.03.2016

หากคุณไม่ได้รับอนุญาตให้ใช้ฟังก์ชันรายการที่มีลำดับสูงกว่า ทางเลือกของคุณคือใช้การเรียกซ้ำ

ตัวอย่างได้ให้กรณีที่คุณต้องการตอบสนองแล้ว:

-- Base case:
split [] = …

-- Recurrence:
split (x : xs) = (do something with x) … (split xs) …
person Konrad Rudolph    schedule 14.09.2010
comment
โปรดทราบว่า @Kenny's และโซลูชันของฉันแก้ไขปัญหาที่แตกต่างกัน ตามที่ @Tom แสดงความคิดเห็นใต้คำถามของคุณ จึงไม่ชัดเจนว่าวิธีแก้ไขปัญหาใดในสองวิธีที่เหมาะกับปัญหาที่แท้จริงของคุณ เนื่องจากตัวอย่างของคุณไม่ชัดเจน - person Konrad Rudolph; 14.09.2010

เมื่อคุณได้วางโซลูชันของคุณแล้ว ฉันจะนำไปใช้ดังนี้:

split xs = (everyother 0 xs, everyother 1 xs)
      where everyother _ []     = []
            everyother 1 (x:xs) = everyother 0 xs
            everyother 0 (x:xs) = x : (everyother 1 xs)

นี่หมายความว่ารายการแรกในรายการคือรายการ 0

person Matt Ellen    schedule 14.09.2010
comment
ใช่ว่าดี. ความคิดที่น่าสนใจ - person Matt; 14.09.2010

ฉันคิดว่ามันเกี่ยวข้องกับ รับทุก ๆ องค์ประกอบที่ N

อย่างไรก็ตาม นี่คือสิ่งที่ฉันจะทำ:

ghci> let split ys = let skip xs = case xs of { [] -> [] ; [x] -> [x] ; (x:_:xs') -> x : skip xs' } in (skip ys, skip . drop 1 $ ys)
ghci> split [1..10]
([1,3,5,7,9],[2,4,6,8,10])

หรือจัดรูปแบบอย่างสวยงาม:

split xs = (skip xs, skip . drop 1 $ xs)
  where 
  skip [] = []
  skip [x] = [x]
  skip (x:_:xs') = x : skip xs'
person sastanin    schedule 14.09.2010

person    schedule
comment
ลายเซ็นของคุณผิดไปเล็กน้อย… - person Konrad Rudolph; 14.09.2010
comment
@คอนราด: ฉันไม่รู้ว่าคุณหมายถึงอะไร ??? ทั้งสองไม่เหมือนกัน และฉันละเว้น 2 กรณีพื้นฐาน - person kennytm; 14.09.2010
comment
ลืมมันซะ… ดูเหมือนว่าฉันไม่ได้ติดต่อกับ Haskell นานเกินไป ดูคำตอบต้นฉบับของฉัน: วงเล็บหายไปรอบตัวสร้างรายการ - person Konrad Rudolph; 14.09.2010
comment
@Konrad: ใช่แล้ว ฟังก์ชั่นที่รับอาร์กิวเมนต์เดียวนั้นไม่เคยได้รับการแก้ไข ;-) - person Tom Lokhorst; 14.09.2010