Hans van der Laan
Hans van der Laan

Reputation: 545

Get X first elements out of list

Let’s consider 2 lists: ["a","b","c"] and ["a","b","c","d","e","f"]

I want to check if the first list is the beginning of the other list I thought I could use:

["a","b","c"] == head (splitAt (length ["a","b","c"]) ["a","b","c","d","e","f"])

Unfortunately this doesn't work. Is there another way to get the first the 3 first elements out of a list in a new list?

Upvotes: 6

Views: 9441

Answers (3)

Toxaris
Toxaris

Reputation: 7266

I want to check if the first list is the beginning of the other list.

You can use isPrefixOf from the Data.List module.

Upvotes: 3

bheklilr
bheklilr

Reputation: 54058

Rather than using take, you could use zipWith to avoid traversing the lists twice. When you call length, you first have to traverse the shorter list, then you take that many values from the longer list, then you traverse the lists, comparing element by element. What would make more sense is to traverse both lists as the same time, stopping your comparison when the shorter one is expired. zipWith provides exactly this functionality:

-- Definitions for `and` and `zipWith` in `Prelude`
--
-- and :: [Bool] -> Bool
-- and [] = True
-- and (x:xs) = x && and xs
--
-- zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
-- zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys
-- zipWith _ _      _      = []

sameStartingElements :: Eq a => [a] -> [a] -> Bool
sameStartingElements xs ys = and $ zipWith (==) xs ys

Thanks to laziness, this definition will only traverse both lists once, and it stops as soon as one of them runs out of elements. This will be somewhat more efficient, and it avoids having to know the length of either list.

Upvotes: 8

Martin Drautzburg
Martin Drautzburg

Reputation: 5243

The function you're looking for is take. See here.

Upvotes: 6

Related Questions