我对这个问题经历了一篇文章,但我不明白。有人能解释吗?列表形式的列表中的每个第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