Jon*_*n W 38 syntax haskell list
Haskell与Python List Slices有相似的语法糖吗?
例如在Python中:
x = ['a','b','c','d']
x[1:3]
Run Code Online (Sandbox Code Playgroud)
给出从索引1到索引2的字符(或排除索引3):
['b','c']
Run Code Online (Sandbox Code Playgroud)
我知道Haskell具有(!!)特定索引的功能,但是是否存在等效的"切片"或列表范围函数?
sep*_*p2k 53
切片列表没有内置函数,但您可以使用drop和自己轻松编写一个take:
slice :: Int -> Int -> [a] -> [a]
slice from to xs = take (to - from + 1) (drop from xs)
Run Code Online (Sandbox Code Playgroud)
应该指出的是,由于Haskell列表是单链表(而python列表是数组),创建这样的子列表将O(to)不同于O(1)python(当然假设整个列表实际得到了评估 - 否则Haskell的懒惰生效) .
Chu*_*uck 16
没有语法糖.如果需要,你可以take和drop.
take 2 $ drop 1 $ "abcd" -- gives "bc"
Run Code Online (Sandbox Code Playgroud)
我不认为有一个,但你可以写一个相当简单:
slice start end = take (end - start + 1) . drop start
Run Code Online (Sandbox Code Playgroud)
当然,前提是start和end在界和end >= start.
Python 切片还支持步骤:
>>> range(10)[::2]
[0, 2, 4, 6, 8]
>>> range(10)[2:8:2]
[2, 4, 6]
Run Code Online (Sandbox Code Playgroud)
受到丹·伯顿 (Dan Burton)删除每个第 N 个元素的启发,我实现了带有步骤的切片。它适用于无限列表!
takeStep :: Int -> [a] -> [a]
takeStep _ [] = []
takeStep n (x:xs) = x : takeStep n (drop (n-1) xs)
slice :: Int -> Int -> Int -> [a] -> [a]
slice start stop step = takeStep step . take (stop - start) . drop start
Run Code Online (Sandbox Code Playgroud)
但是,Python 还支持负开始和停止(从列表末尾开始计数)和负步骤(反转列表,停止变为开始,反之亦然,并逐步遍历列表)。
from pprint import pprint # enter all of this into Python interpreter
pprint([range(10)[ 2: 6], # [2, 3, 4, 5]
range(10)[ 6: 2:-1], # [6, 5, 4, 3]
range(10)[ 6: 2:-2], # [6, 4]
range(10)[-8: 6], # [2, 3, 4, 5]
range(10)[ 2:-4], # [2, 3, 4, 5]
range(10)[-8:-4], # [2, 3, 4, 5]
range(10)[ 6:-8:-1], # [6, 5, 4, 3]
range(10)[-4: 2:-1], # [6, 5, 4, 3]
range(10)[-4:-8:-1]]) # [6, 5, 4, 3]]
Run Code Online (Sandbox Code Playgroud)
我如何在 Haskell 中实现它?如果步骤为负数,我需要反转列表,如果这些为负数,则从列表末尾开始计数开始和停止,并记住结果列表应包含索引start <= k < stop的元素(正数)步骤)或开始 >= k > 停止(负步骤)。
takeStep :: Int -> [a] -> [a]
takeStep _ [] = []
takeStep n (x:xs)
| n >= 0 = x : takeStep n (drop (n-1) xs)
| otherwise = takeStep (-n) (reverse xs)
slice :: Int -> Int -> Int -> [a] -> [a]
slice a e d xs = z . y . x $ xs -- a:start, e:stop, d:step
where a' = if a >= 0 then a else (length xs + a)
e' = if e >= 0 then e else (length xs + e)
x = if d >= 0 then drop a' else drop e'
y = if d >= 0 then take (e'-a') else take (a'-e'+1)
z = takeStep d
test :: IO () -- slice works exactly in both languages
test = forM_ t (putStrLn . show)
where xs = [0..9]
t = [slice 2 6 1 xs, -- [2, 3, 4, 5]
slice 6 2 (-1) xs, -- [6, 5, 4, 3]
slice 6 2 (-2) xs, -- [6, 4]
slice (-8) 6 1 xs, -- [2, 3, 4, 5]
slice 2 (-4) 1 xs, -- [2, 3, 4, 5]
slice (-8)(-4) 1 xs, -- [2, 3, 4, 5]
slice 6 (-8)(-1) xs, -- [6, 5, 4, 3]
slice (-4) 2 (-1) xs, -- [6, 5, 4, 3]
slice (-4)(-8)(-1) xs] -- [6, 5, 4, 3]
Run Code Online (Sandbox Code Playgroud)
该算法仍然适用于给定正参数的无限列表,但如果使用负步骤,它会返回一个空列表(理论上,它仍然可以返回一个反向子列表),如果使用负开始或停止,它会进入无限循环。所以要小心消极的论点。
小智 5
我遇到了类似的问题并使用了列表理解:
-- Where lst is an arbitrary list and indc is a list of indices
[lst!!x|x<-[1..]] -- all of lst
[lst!!x|x<-[1,3..]] -- odd-indexed elements of lst
[lst!!x|x<-indc]
Run Code Online (Sandbox Code Playgroud)
也许不像 python 的切片那么整洁,但它可以完成这项工作。请注意, indc 可以按任何顺序排列,不必连续。
如前所述,Haskell 使用 LINKED 列表使这个函数 O(n) 其中 n 是访问的最大索引,而不是依赖于值数量的python 切片访问。
免责声明:我还是 Haskell 的新手,我欢迎任何更正。