1

I am trying to write a very simple function that takes a list (for example : [1,2,3,1,5]) and returns a list of elements that are directly after a specific element.

What I have reached so far is:

function element list = filter (\x -> element:x) list

My desired output:

function 1 [1,2,3,1,5]

=>   [2,5]

3
  • By "next to", I assume you mean "after", correct? Commented Apr 14, 2016 at 19:08
  • exactly; The specified element direclty precedes the desired element Commented Apr 14, 2016 at 19:13
  • w/ list comprehensions this is foo a xs = [y | (x:y:_) <- tails xs, x==a]. tails is from Data.List. Commented Apr 15, 2016 at 7:49

3 Answers 3

5

Try this

map snd $ filter ((== x) . fst) $ zip theList (tail theList)

This won't work on an empty list, you will still need extra code to deal with that.


How does this work?

First, note that the values flow from right to left. The ($) operator allows this to happen. So, the first part evaluated is the zip function.

zip theList (tail theList)

For your example above, this would yield

zip [1,2,3,1,5] [2,3,1,5]

equaling

[(1,2), (2, 3), (3, 1), (1,5)]

which is the set of concurrent pairs in the list.

Next, the filter is applied

filter ((== x) . fst) $ ....

In English, what this says is, filter out only the concurrent pairs whose first element equals x. The output is

[(1,2), (1,5)]

Now we have the list of concurrent pairs starting with 1.

Finally, we apply the map

map snd $ ....

This just pulls out the second value of the pair.

map snd [(1,2), (1,5)] = [2,5]

which is the desired value.


Note, my comment above about failing on the empty list.

This is because tail crashes on the empty list

tail [] --error

There are ways to patch this behavior (see the safe package, for instance), but it is mostly bookkeeping at this point, so I left that for you to work out.


Also note that since all of the functions we used are lazy, this approach would work for lists of infinite length as well.

Sign up to request clarification or add additional context in comments.

1 Comment

just replace tail with drop 1 and it'll work for empty lists too.
0

You can do this quite easily with a simple list comprehension, e.g.:

successors xs i = [y | (x,y) <- zip xs (drop 1 xs), x == i]

Comments

0

This will work to your specifications

next x (i:y:ys) -- look at the first two items in the list
    | x == i = -- if the first item == x, 
        y : next x (y:ys) -- take the second, and continue minus the first element
    |otherwise = -- not equal, 
        next x (y:ys) -- so skip that element
next _ [_] = [] -- if there's no second element, then stop
next _ _ = [] -- if the list is empty, stop

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.