由於有一種方法通過模式匹配綁定列表的頭部和尾部,我想知道是否可以使用模式匹配來綁定列表的最後一個元素?您可以使用模式匹配來綁定列表的最後一個元素嗎?
回答
是的,您可以使用ViewPatterns
擴展名。
Prelude> :set -XViewPatterns
Prelude> let f (last -> x) = x*2
Prelude> f [1, 2, 3]
6
注意,這種模式將始終成功,雖然如此,你可能會想增加一個模式的情況下列表是空的,否則last
會拋出異常。
Prelude> f []
*** Exception: Prelude.last: empty list
另請注意,這只是語法糖。與正常模式匹配不同,這是O(n),因爲您仍在訪問單向鏈接列表的最後一個元素。如果您需要更高效的訪問權限,請考慮使用不同的數據結構,例如Data.Sequence
,它提供對兩端的訪問權限O(1)。
您可以使用ViewPatterns
做圖案在列表的末尾匹配,所以讓我們做
{-# LANGUAGE ViewPatterns #-}
,並使用reverse
作爲viewFunction,因爲它總是成功,因此,例如
printLast :: Show a => IO()
printLast (reverse -> (x:_)) = print x
printLast _ = putStrLn "Sorry, there wasn't a last element to print."
這是安全的,只要你覆蓋所有的可能性,它不會拋出任何異常。 (你可以重寫它返回一個Maybe
,例如。)
語法
mainFunction (viewFunction -> pattern) = resultExpression
是語法糖
mainFunction x = case viewFunction x of pattern -> resultExpression
這樣可以真正看到它反轉名單然後模式匹配,但它感覺更好。 viewFunction
只是你喜歡的任何功能。 (一個擴展的目的之一是讓人們能夠乾淨,容易使用存取模式匹配功能 所以他們沒有使用他們的數據類型的基礎結構時 其上定義的功能。)
其他答案解釋了基於ViewPatterns
的解決方案。如果你想使之更加的模式匹配狀,你可以包成PatternSynonym
:
tailLast :: [a] -> Maybe ([a], a)
tailLast [email protected](_:_) = Just (init xs, last xs)
tailLast _ = Nothing
pattern Split x1 xs xn = x1 : (tailLast -> Just (xs, xn))
,然後寫你的功能例如
foo :: [a] -> (a, [a], a)
foo (Split head mid last) = (head, mid, last)
foo _ = error "foo: empty list"
這是我的Haskell編程的第一天,我也遇到了同樣的問題,但我無法解析使用某種外部神器在以前的解決方案建議。
我對Haskell的感覺是,如果核心語言沒有針對您的問題的解決方案,那麼解決方案就是轉換問題直到它適用於該語言。
在這種情況下,轉換問題意味着將尾部問題轉換爲頭部問題,這似乎是模式匹配中唯一受支持的操作。它可以很容易地使用列表反轉來做到這一點,然後使用head元素在反轉列表上工作,就像在原始列表中使用tail元素一樣,最後,如果需要,將結果還原爲初始順序(例如if這是一個列表)。例如,給定一個整數列表(例如[1,2,3,4,5,6]),假設我們要構建這個列表,其中原始列表的每個第二個元素從結尾開始被其雙倍數(取自this excellent introduction to Haskell的Homework1的鍛鍊)取代:[2,2,6,4,10,6]。
然後我們可以使用以下命令:
revert :: [Integer] -> [Integer]
revert [] = []
revert (x:[]) = [x]
revert (x:xs) = (revert xs) ++ [x]
doubleSecond :: [Integer] -> [Integer]
doubleSecond [] = []
doubleSecond (x:[]) = [x]
doubleSecond (x:y:xs) = (x:2*y : (doubleSecond xs))
doubleBeforeLast :: [Integer] -> [Integer]
doubleBeforeLast l = (revert (doubleSecond (revert l)))
main = putStrLn (show (doubleBeforeLast [1,2,3,4,5,6,7,8,9]))
這顯然比以前的解決方案更長的時間,但感覺更哈斯克爾十歲上下給我。
歡迎來到StackOverflow,並祝賀這麼好的開始!反轉列表以訪問遠端實際上是一個非常Haskellish的解決方案(雖然效率相當低,但如果您需要多次執行,使用'last'可能會更糟......如果性能很關鍵並且需要訪問最後一個元素,那麼列表不是合適的類型)。 – leftaroundabout
謝謝。在我的新手水平上,我確實更感興趣的是發現Haskell編程習慣用法,而不是對它們的性能影響進行測試。我同意,嘗試以相反順序使用簡單鏈接列表是一種更糟的情況,我想這實際上是Haskell首先不提供尾部模式匹配的原因。 (Haskell列表是使用簡單鏈接列表實現的,對嗎?) – OlivierD
正確。 Haskell列表非常適合堆棧或無限流,但它們對於隨機訪問來說真的很糟糕,訪問遠端並不比訪問中間的任何元素更好。 – leftaroundabout
- 1. 模式匹配找到列表的最後一個元素
- 2. Haskell,一個列表中的兩個元素後跟一個元素的其他列表? (模式匹配)
- 3. 列表元素上的模式匹配
- 4. 匹配分隔列表中的最後一個元素?
- 5. Scala使用模式匹配獲取列表的第一個和最後一個元素
- 6. Ocaml模式一次匹配列表中的多個元素
- 7. 可以找到第一個或最後一個匹配嗎?
- 8. Scala模式匹配:如何匹配列表中的元素?
- 9. Python中模式匹配後的打印列表元素
- 10. 模式匹配時可以使用變量的值而不是綁定嗎?
- 11. 如何對列表中的元素使用模式匹配?
- 12. 在模式匹配中,我可以使用匹配的模式嗎?
- 13. 與Haskell中的2個元素匹配的模式匹配列表
- 14. 使用模式匹配和遞歸在列表中查找最大元素F#
- 15. jQuery:在指定元素之前選擇最後一個匹配
- 16. 在Perl中匹配最後一個正則表達式模式
- 17. selenium xpath,如何選擇表中最後一個匹配元素?
- 18. 使用float後列表的最後一個元素:right
- 19. 匹配從一個列表到另一個列表中的元素,跳過已匹配的元素,Python
- 20. 正則表達式來查找匹配列表中的元素
- 21. 正則表達式匹配最後一個元素和新行的第一個元素
- 22. 如果使用綁定來刪除元素,可以使用knockout.js嗎?
- 23. 使用XSLT來包裝的元素,但不包括最後一個匹配的元素
- 24. 我可以使用正則表達式來匹配一組值嗎?
- 25. PHP的正則表達式匹配模式匹配的最後一次出現
- 26. 模式匹配列表尾部元組元素
- 27. 2個列表上的匹配元素
- 28. Python,匹配兩個列表的元素
- 29. Vim tabularize插件可以匹配每列多個表達式嗎?
- 30. 我可以綁定到使用jquery.load()加載的元素嗎?
last在空列表上拋出異常。我期待擺脫最後,頭,fst,snd。不能很好地處理空列表的函數。模式匹配,例如,讓(x:xs)=「abcdefg」是我在我的問題中提到的。希望有一個類似的方法來獲得最後一個元素,而不使用不安全的前奏功能。 –
@MichaelLitchard:嗯,你可以例如定義一個'safeLast'函數,它返回一個'Maybe',然後你可以進行模式匹配,或者也許只是反轉列表,然後使用正常的模式匹配。 – hammar
,因爲它總是成功,它根本不是什麼「模式匹配」。 'f =(* 2)。最後'更好。 – u0b34a0f6ae