1

Imagine a nested list as below.

["A","ABBA","ABABA"]

I would like to create a function which removes singleton elements from this list (in this example, "A"), and removes any lists containing that singleton element.

So that:

removeElems ["A","ABBA","CCC"] -> ["CCC"]

Below is my attempt at solving this problem:

badElements nested = concat $ filter (\c -> length c == 1) nested

removeElements nested = [c | c <- nested, u <- badElements nested, not $ any (==u) c]

This produces strange results where the multiple generators 'cycle' the nested list, such as below:

["A","ABBA","C","BCCB"] --> ["A","A","ABBA","ABBA","C","C","BCCB","BCCB"]--> ["A","ABBA","C","BCCB"]

Another example:

[[1],[1,2,3,4],[2],[5,6,7,8]] --> [5,6,7,8]
4
  • 1
    Define "strange results". Also, by De Morgan not $ any (== u) is better written as all (/= u). Commented Feb 7, 2011 at 15:42
  • What do you define as a "bad element?" Should "A" be removed because it appears in the outer list? Could you please add some more examples of what you want the output to be like? Commented Feb 7, 2011 at 15:43
  • @delnan actually it's better written simply as notElem u, which is defined just like you wrote it, notElem x = all (/= x) source Commented Feb 7, 2011 at 16:52
  • @Dan: Thanks, my stdlib-fu is weak. Commented Feb 7, 2011 at 16:53

3 Answers 3

2

Since you only want to produce zero or one outputs for each list element, you don't want a list comprehension that iterates over badElements. Instead, you want to filter on a predicate that iterates over badElements.

What predicate? Well, a list is good if it doesn't contain a bad element. That is, all of its elements are not bad.

removeElements nested = filter (all (`notElem` badElements nested)) nested
Sign up to request clarification or add additional context in comments.

Comments

2

Here's an untested attempt at it:

removeElements ls = filter (null . intersect singletons) ls
                    where singletons = mapMaybe singleElem ls
                          singleElem [x] = Just x
                          singleElem _ = Nothing

2 Comments

Or, without maybes, you could write singletons = let s [x] = True; s _ = False in filter s (where singletons is now a function [[x]] -> [[x]])
In my code, singletons is a list, not a function (since it has the ls on the end of the mapMaybe). I used mapMaybe to avoid needing to flatten the list of singletons, but I agree that concat $ filter ... ls works too.
1

Another attempt:

badElements :: [[a]] -> [a]
badElements = concat . filter (\x -> 1 == length x)

removeBadElements :: (Eq a) => [[a]] -> [[a]]
removeBadElements xs = filter (\x -> not $ any ((flip elem) x) (badElements xs) ) xs

badElements will return a list with all the singleton elements of its parameter (similar to what your badElements is supposed to do:

badElements [[1],[1,2,3,4],[2],[5,6,7,8]]
[1,2]

removeBadElements, then, removes all the elements that contain an element of badElements.

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.