我對這個問題經歷了一篇文章,但我不明白。有人能解釋嗎?列表形式的列表中的每個第n個元素
問:從第n個元素本身開始以列表的形式查找列表中的每個第n個元素。
everyNth :: Int -> [t] -> [t]
everyNth elt = map snd . filter (\(lst,y) -> (mod lst elt) == 0) . zip [1..]
此外,請解釋如何使用模式匹配來解決此問題。即使用
[]->[]
我對這個問題經歷了一篇文章,但我不明白。有人能解釋嗎?列表形式的列表中的每個第n個元素
問:從第n個元素本身開始以列表的形式查找列表中的每個第n個元素。
everyNth :: Int -> [t] -> [t]
everyNth elt = map snd . filter (\(lst,y) -> (mod lst elt) == 0) . zip [1..]
此外,請解釋如何使用模式匹配來解決此問題。即使用
[]->[]
它易於使用模式匹配「中,選擇每n個元素」爲n個特殊情況:
every2nd (first:second:rest) = second : every2nd rest
every2nd _ = []
-- >>> every2nd [1..12]
-- [2,4,6,8,10,12]
every3rd (first:second:third:rest) = third : every3rd rest
every3rd _ = []
-- >>> every3rd [1..13]
-- [3,6,9,12]
every4th (first:second:third:fourth:rest) = fourth : every4th rest
every4th _ = []
-- >>> every4th [1..12]
-- [4,8,12]
對於一般的情況下,雖然,我們的運氣了,至少用那種特殊的方法。上述模式需要一定的長度才能成爲明確的模式。將所組成的功能你提到從想法開始,我們知道如何尋找的[1..]
每一個第n個成員,即如果它是n的倍數
multiple n m = m `mod` n == 0
-- >>> filter (multiple 3) [1..12]
-- [3,6,9,12]
所以,你正試圖解決明白拉鍊[1..]
與列表
index xs = zip [1..] xs
-- >>> index [1..5]
-- [(1,1),(2,2),(3,3),(4,4),(5,5)]
-- >>> index "hello"
-- [(1,'h'),(2,'e'),(3,'l'),(4,'l'),(5,'o')]
然後過濾掉那些只是其對第一個元素是n的倍數
every_nth_with_index n xs = filter (\(m,a) -> multiple n m) (index xs)
-- >>> every_nth_with_index 3 [1..12]
-- [(3,3),(6,6),(9,9),(12,12)]
-- >>> every_nth_with_index 3 "stackoverflow.com"
-- [(3,'a'),(6,'o'),(9,'r'),(12,'o'),(15,'c')]
然後擺脫的附屬建築,留給我們只是每對的第二個元素:
every_nth n xs = map snd (every_nth_with_index n xs)
-- >>> every_nth 3 [1..12]
-- [3,6,9,12]
-- >>> every_nth 3 "stackoverflow.com"
-- "aoroc"
Retracinging我們的腳步,我們看到,這是一樣的
everyNth elt = map snd . filter (\(lst,y) -> (mod lst elt) == 0) . zip [1..]
隨着一點點的欺騙,你可以使用定義everyNth
模式匹配。真的,正如邁克爾的回答中指出的那樣,我們正在抽象出難以進行模式匹配的部分。
everyNth n lst = e (shorten lst)
where shorten = drop (n-1) -- here's the cheat
e [] = []
e (first:rest) = first : e (shorten rest)
臭名昭着的扇子再次襲擊。
everyNth n xs = foldr go (`seq` []) xs n where
go x r 0 = x : r (n - 1)
go _ r k = r (k - 1)
這是非常相似的,但chepner's approach它集成滴入遞歸。重寫沒有摺疊,它是純粹的模式匹配:
everyNth n = go n where
go k [] = k `seq` []
go 0 (x : xs) = x : go (n - 1) xs
go k (_ : xs) = go (k - 1) xs
第一場比賽是否等同於'go!k [] = []'? – chepner
關閉主題(沒有模式匹配)我認爲以下內容可以很好地讀出'everyNth n =地圖頭。 takeWhile(非null)。 iterate(drop n)' – Cirdec
@Cirdec,我不太在乎不必要的部分函數,而且我是列表融合的粉絲。我不知道是否有一種特別漂亮的方式來融合。如果我們把'takeWhileJust ::(a - > Maybe b) - > [a] - > [b]'with'takeWhileJust f(x:xs)|只要y < - f x = y:takeWhileJust f xs; takeWhileJust _ _ = []'。 – dfeuer
如果你以前從未見過Haskell,那麼這需要一點解釋。
everyNth :: Int -> [t] -> [t]
everyNth elt = map snd . filter (\(lst,y) -> (mod lst elt) == 0) . zip [1..]
首先,請注意該類型有兩個參數,但定義只有一個。這是因爲everyNth
返回的值實際上是另一個函數。 elt
是Int,並且第二行中的表達式創建了執行該作業的新函數。
二,注意「。」運營商。這是一個連接兩個功能的運算符。它的定義是這樣的:
(f . g) x = f (g x)
這裏是第二個參數定義的等價版本作出了明確:
everyNth elt xs = map snd (filter (\(lst y) -> (mod lst elt) == 0) (zip xs))
當你看到通過鏈接鏈一堆的功能「」您需要從右向左閱讀它。在我的第二個版本中,請注意支架嵌套。 zip [1..] xs
是最內在的表達,所以它首先得到評估。它將["foo", "bar"]
這樣的列表變成[(1, "foo"),(2, "bar")]
。然後對其進行過濾,以找到數量爲elt
的倍數的條目。最後,map snd
將數字取消以僅返回所需的條目。
我們可以在這裏解釋很多東西,也許你想對你不明白的東西更精確一點?另外,它有助於你開始解釋你的理解...... – Alec
我理解第一行,對於第二行,我認爲它採用elt,如果mod結果等於零,則將它從尾部映射到頭部,然後它將特定元素拉到列表中。 – Arushi
下面是一個密切相關的解決方案:'nths n = catMaybes.zipWith($)(tail.cycle $ Just:replicate(n-1)(const Nothing))''。隨意比較和對比 - 然後告訴我們缺少什麼。如果這是一項家庭作業,請隨意使用它,以防止自己的危險。我甚至會拋出另一種相關方法的高爾夫版本。玩的開心。 '\ n-> concat.zipWith($)(cycle $([2..n] >> [const []])++ [(:[])])' – MarLinn