Haskell有List List(即Python)吗?

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的懒惰生效) .

  • @rampion:这是对中缀运算符的另一种有趣滥用:`(!>)= drop`,`(<!)= flip take`,确保后者具有更高的固定性.现在你可以像这样分割列表:`2!> ['a'..'z'] <!5` =`"cde"`.但这变得非常愚蠢. (16认同)
  • 如果`slice 1 2 ['a','b','c','d']`对你来说太冗长了,你也可以添加你自己的糖`xs!@(from,to)= slice ft xs` ,所以你可以做'['a','b','c','d']!@(1,2)` (7认同)
  • 我喜欢``map("abcd"!!)[1 .. 2]``(获得"bc"),即使它是非常低效(二次)的时间.("喜欢"在"可爱"的意义上;因为二次方,我在实践中从不使用它.) (6认同)

Tho*_*son 34

如果您正在尝试匹配Python"列表"(这不是列表,正如其他人所说),那么您可能希望使用具有内置切片的Haskell 向量包.此外,可以并行评估,我认为这真的很酷.Vector


Chu*_*uck 16

没有语法糖.如果需要,你可以takedrop.

take 2 $ drop 1 $ "abcd" -- gives "bc"
Run Code Online (Sandbox Code Playgroud)


Sco*_*est 9

我不认为有一个,但你可以写一个相当简单:

slice start end = take (end - start + 1) . drop start
Run Code Online (Sandbox Code Playgroud)

当然,前提是startend在界和end >= start.


Mir*_*lov 6

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 的新手,我欢迎任何更正。

  • 我不确定 Haskell 的惰性求值会如何影响这一点(如果有的话),但我认为如果您以相反的顺序访问元素,它可能是 O(n^2),因为 Haskell 的列表是单向链接的;因此,对于每个元素,您需要遍历整个列表直到该元素。 (2认同)