Does Haskell have similar syntactic sugar to Python List Slices?
For instance in Python:
x = [\'a\',\'b\',\'c\',\'d\']
x[1:3]
give
I had a similar problem and used a list comprehension:
-- 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]
Perhaps not as tidy as python's slices, but it does the job. Note that indc can be in any order an need not be contiguous.
As noted, Haskell's use of LINKED lists makes this function O(n) where n is the maximum index accessed as opposed to python's slicing which depends on the number of values accessed.
Disclaimer: I am still new to Haskell and I welcome any corrections.
When I want to emulate a Python range (from m to n) in Haskell, I use a combination of drop & take:
In Python:
print("Hello, World"[2:9]) # prints: "llo, Wo"
In Haskell:
print (drop 2 $ take 9 "Hello, World!") -- prints: "llo, Wo"
-- This is the same:
print (drop 2 (take 9 "Hello, World!")) -- prints: "llo, Wo"
You can, of course, wrap this in a function to make it behave more like Python. For example, if you define the !!! operator to be:
(!!!) array (m, n) = drop m $ take n array
then you will be able to slice it up like:
"Hello, World!" !!! (2, 9) -- evaluates to "llo, Wo"
and use it in another function like this:
print $ "Hello, World!" !!! (2, 9) -- prints: "llo, Wo"
I hope this helps, Jon W.
No syntactic sugar. In cases where it's needed, you can just take
and drop
.
take 2 $ drop 1 $ "abcd" -- gives "bc"
Obviously my foldl version loses against the take-drop approach, but maybe someone sees a way to improve it?
slice from to = reverse.snd.foldl build ((from, to + 1), []) where
build res@((_, 0), _) _ = res
build ((0, to), xs) x = ((0, to - 1), x:xs)
build ((from, to), xs) _ = ((from - 1, to - 1), xs)
There's no built-in function to slice a list, but you can easily write one yourself using drop
and take
:
slice :: Int -> Int -> [a] -> [a]
slice from to xs = take (to - from + 1) (drop from xs)
It should be pointed out that since Haskell lists are singly linked lists (while python lists are arrays), creating sublists like that will be O(to)
, not O(to - from)
like in python (assuming of course that the whole list actually gets evaluated - otherwise Haskell's laziness takes effect).
Why not use already existing Data.Vector.slice
together with Data.Vector.fromList
and Data.Vector.toList
(see https://stackoverflow.com/a/8530351/9443841)
import Data.Vector ( fromList, slice, toList )
import Data.Function ( (&) )
vSlice :: Int -> Int -> [a] -> [a]
vSlice start len xs =
xs
& fromList
& slice start len
& toList