2017-12-18 224 views
2

我想在地圖內使用'head'函數。 問題是'head'函數只接受非空列表。 我有名單列表:空列表問題的頭函數

let ll =[["dog", "cat"], ["pig", "cow"], []] 

我需要遍歷目錄列表中兩次

let listOne = filter(\x -> if length x > 0) ll 
map(\x -> head x) listOne 

我不知道我是否能一次迭代列表的列表或把一個「如果條件」沒有「過濾器」的地圖裏面

任何建議,將不勝感激。

+1

你想爲空列表發生什麼?只是過濾/忽略它?爲什麼過濾器不能做你想要的? – puhlen

+0

過濾器僅刪除空列表,但我想使用'head'並在head元素上執行一些操作。 –

+0

但是一個空的列表沒有頭。你需要那個地圖+濾鏡不能做什麼?如果你只關心兩次迭代列表,它不會。這些行動是懶惰評估的。 – puhlen

回答

8

是的,其實你可以把它寫成一個列表理解聲明,並使用模式,而不是匹配

result = [ h | (h:_) <- ll ] 

或作爲一個函數:

heads :: [[a]] -> [a] 
heads ll = [ h | (h:_) <- ll ] 

所以在這裏,我們使用匹配所有非空列表的模式(h:_),我們直接獲得此列表的頭部h並將其添加到列表中。如果您在列表理解中使用模式(在左側的箭頭<-的左側,它將跳過與模式不匹配的元素)。

這也比使用length安全的,因爲length會卡住進入無限循環,如果你是無限名單的工作。此外,通過在非全部函數上使用模式,我們有更多的句法保證這個函數將起作用(是的,一旦非空元素被過濾,我們當然確定head不會導致錯誤,但是我們只知道這是因爲我們有關於head函數的信息)。

請注意,由於您使用if而沒有thenelse部分,因此您的嘗試將導致語法錯誤。

或者,我們可以像@DanielWagner說,不同的使用寫heads功能,比如:

heads :: [[a]] -> [a] 
heads ll = concatMap (take 1) ll 

,或者使用列表單子的綁定

heads :: [[a]] -> [a] 
heads = (take 1 =<<) 

或我們可以調換2d列表。在這種情況下,第一行包含列表的所有頭部。由於不能保證有這樣的行,所以我們可以在末尾附加一個空列表,如:

heads :: [[a]] -> [a] 
heads = head . (++ [[]]) . transpose 
+2

同一想法的另一個有趣拼寫:'heads = concatMap(take 1)'。一個完全不同的想法:'頭=頭。 (++ [[]])。 transpose'。 –

+0

@DanielWagner:我非常喜歡這些:),尤其是第一個。 –