我找到了这个问题的帖子,但我不明白。有人可以解释一下吗?
问:以列表的形式从第n个元素本身开始查找列表中的每个第n个元素。
everyNth :: Int -> [t] -> [t]
everyNth elt = map snd . filter (\(lst,y) -> (mod lst elt) == 0) . zip [1..]
另外,请解释如何将模式匹配用于此问题。那是用
[]->[]
答案 0 :(得分:3)
对于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"
回顾我们的步骤,我们发现这与
相同everyNth elt = map snd . filter (\(lst,y) -> (mod lst elt) == 0) . zip [1..]
答案 1 :(得分:2)
稍微作弊,您可以使用模式匹配来定义everyNth
。实际上,正如迈克尔的回答所指出的那样,我们正在抽象出使模式匹配变得困难的部分。
everyNth n lst = e (shorten lst)
where shorten = drop (n-1) -- here's the cheat
e [] = []
e (first:rest) = first : e (shorten rest)
答案 2 :(得分:2)
臭名昭着的折扇再次袭来。
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
答案 3 :(得分:1)
如果您之前从未见过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
将数字删除,只返回所需的条目。