2016-08-19 184 views
0

我对这个问题经历了一篇文章,但我不明白。有人能解释吗?列表形式的列表中的每个第n个元素

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

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

此外,请解释如何使用模式匹配来解决此问题。即使用

[]->[] 
+1

我们可以在这里解释很多东西,也许你想对你不明白的东西更精确一点?另外,它有助于你开始解释你的理解...... – Alec

+0

我理解第一行,对于第二行,我认为它采用elt,如果mod结果等于零,则将它从尾部映射到头部,然后它将特定元素拉到列表中。 – Arushi

+0

下面是一个密切相关的解决方案:'nths n = catMaybes.zipWith($)(tail.cycle $ Just:replicate(n-1)(const Nothing))''。随意比较和对比 - 然后告诉我们缺少什么。如果这是一项家庭作业,请随意使用它,以防止自己的危险。我甚至会抛出另一种相关方法的高尔夫版本。玩的开心。 '\ n-> concat.zipWith($)(cycle $([2..n] >> [const []])++ [(:[])])' – MarLinn

回答

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" 

Retracinging我们的脚步,我们看到,这是一样的

everyNth elt = map snd . filter (\(lst,y) -> (mod lst elt) == 0) . zip [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) 
+0

作为奖励,这种方式是有效的! – dfeuer

+0

一个抱怨:​​模式匹配在这里永远不会失败。看到我的答案。 – dfeuer

+0

这改善了组合方法的效率,至少在我检查的构图中...'everyNth n = map snd。过滤器fst。 zip(circ n)where circ n = drop 1 $ cycle(True:replicate(n-1)False)' – Michael

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 
+0

第一场比赛是否等同于'go!k [] = []'? – chepner

+0

关闭主题(没有模式匹配)我认为以下内容可以很好地读出'everyNth n =地图头。 takeWhile(非null)。 iterate(drop n)' – Cirdec

+0

@Cirdec,我不太在乎不必要的部分函数,​​而且我是列表融合的粉丝。我不知道是否有一种特别漂亮的方式来融合。如果我们把'takeWhileJust ::(a - > Maybe b) - > [a] - > [b]'with'takeWhileJust f(x:xs)|只要y < - f x = y:takeWhileJust f xs; takeWhileJust _ _ = []'。 – dfeuer

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将数字取消以仅返回所需的条目。

相关问题