列表形式的列表中的每个第n个元素

时间:2016-08-19 02:19:33

标签: haskell

我找到了这个问题的帖子,但我不明白。有人可以解释一下吗?

问:以列表的形式从第n个元素本身开始查找列表中的每个第n个元素。

everyNth :: Int -> [t] -> [t]
everyNth elt = map snd . filter (\(lst,y) -> (mod lst elt) == 0) . zip [1..] 

另外,请解释如何将模式匹配用于此问题。那是用

[]->[]

4 个答案:

答案 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将数字删除,只返回所需的条目。