List included in another list in haskell - string

I want to see if a list is included in another list and extract that list from a list of lists, for example i want to see if ["bc","abc"] is included in [["a","b","c","a","b","c","de"],["a","bc","abc","de"],["a","bc","abc","d","e"],....] and i want to make a list of the lists that contian that particular list like [["a","bc","abc","de"],["a","bc","abc","d","e"]] .
for [["aabbcc","aacc"]] I want to match only something like this ["cc","aabbcc","aacc"] or ["c","c","aabbcc","aacc"] but not [["ccaabbcc","aacc"]].
Can someone help me?

From what I understand you want something that cares for the order of the elements in the list
If you DO care the order of elements:
import Data.List (subsequences)
included :: Eq a => [a] -> [[a]] -> [[a]]
included ls nest = filter (\x -> any (ls==) $ subsequences x) nest
TEST:
*Main> included [1,2,3,4] [[1,3,4,5,2],[1,2,4,5],[1,2,3,4,5]]
[[1,2,3,4,5]]
If you do NOT care the order of elements:
import Data.List (subsequences, permutations, concat)
included :: Eq a => [a] -> [[a]] -> [[a]]
included ls nest = filter func nest
where
func x = any (ls==) $ concat $ map subsequences $ permutations x
TEST:
*Main> included [1,2,3,4] [[1,3,4,5,2],[1,2,4,5],[1,2,3,4,5]]
[[1,3,4,5,2],[1,2,3,4,5]]

Assuming that the answer to my question in the comments is no,
import Data.List
g :: (Eq a) => [a] -> [[a]] -> [[a]]
g a xs = [x | x <- xs,
or [and . map (uncurry (==)) $ zip a y | y <- init $ tails x]]
Testing:
Prelude Data.List> g ["bc","abc"] [["a","bc","a","abc","de"],["a","bc","abc","de
"],["a","bc","abc","d","e"]]
[["a","bc","abc","de"],["a","bc","abc","d","e"]]

Assuming that the answer to Will's question in the comments is “no”:
import Data.List (isInfixOf)
foo :: Eq a => [a] -> [[a]] -> [[a]]
foo needle haystack = filter (needle `isInfixOf`) haystack
(Untested.)

Related

Filter Duplicate elements from a [[String]] Haskell

I have a list in the form [["A1","A1","A1"] .. ["G3","G3","G3"]] which contains many duplicate elements like ["A1","A2","A3"] and ["A3","A2","A1"].
How do I filter out such duplicate elements?
if check the above two elements for equality, it shows false
*Main> ["A1","A2","A3"] == ["A3","A2","A1"]
False
nubBy :: (a -> a -> Bool) -> [a] -> [a] is a relevant function that removes duplicates from a list via an arbitrary equality test.
A version of the function you're looking for is:
import Data.List (sort, nubBy)
removeDuplicates' :: Ord a => [[a]] -> [[a]]
removeDuplicates' = nubBy (\l1 l2 = sort l1 == sort l2)
Of course, this does require that a is an Ord, not just an Eq, as well as using sort, which is (as stated below) an expensive function. So it is certainly not ideal. However, I don't know specifically how you want to do the equality tests on those lists, so I'll leave the details to you.
#AJFarmar's answer solves the issue. But it can be done a bit more efficient: since sort is an expensive function. We want to save on such function calls.
We can use:
import Data.List(nubBy, sort)
import Data.Function(on)
removeDuplicates' :: Ord a => [[a]] -> [[a]]
removeDuplicates' = map snd . nubBy ((==) `on` fst) . map ((,) =<< sort)
what we here do is first construct a map ((,) =<< sort). This means that for every element x in the original list, we construct a tuple (sort x,x). Now we will perform a nubBy on the first elements of the two tuples we want to sort. After we have sorted, we will perform a map snd where we - for every tuple (sort x,x) return the second item.
We can generalize this by constructing a nubOn function:
import Data.List(nubBy)
import Data.Function(on)
nubOn :: Eq b => (a -> b) -> [a] -> [a]
nubOn f = map snd . nubBy ((==) `on` fst) . map ((,) =<< f)
In that case removeDuplicates' is nubOn sort.
You may not even need to sort. You just need to see if all items are the same like;
\xs ys -> length xs == (length . filter (== True) $ (==) <$> xs <*> ys)
you just need to know that (==) <$> ["A1","A2","A3"] <*> ["A3","A2","A1"] would in fact return [False,False,True,False,True,False,True,False,False]
As per #rampion 's rightful comment let's take it further and import Data.Set then it gets pretty dandy.
import Data.Set as S
equity :: Ord a => [a] -> [a] -> Bool
equity = (. S.fromList) . (==) . S.fromList
*Main> equity ["A1","A2","A3"] ["A3","A2","A1"]
True

Define concat function for Digits

I have a list chars and I would like to concat all characters, which are digits and which are next to each other
For example: ['1','5','+','2','4'] => ["15","+","24"]
concat1 :: [Char] -> [Char] -> [String]
concat1 [] [] = []
concat1 [a] [b]
| (isDigit a) && (isDigit b) = [a] ++ [b]
I tried to write this code, but it doesn't seem to be right approach and debugger tells me this:
Couldn't match type `Char' with `[Char]'
Expected type: [String]
Actual type: [Char]
* In the expression: [a] ++ [b]
In an equation for `concat1':
concat1 [a] [b] | (isDigit a) && (isDigit b) = [a] ++ [b]
The type of concat1 is wrong: your example indicates you want one input list and an output list. The input list (ex: ['1','5','+','2','4']) is of type [Char] and the output (ex: ["15","+","24"]) of type [String]. That gives the signature
concat1 :: [Char] -> [String]
For the implementation, you probably want to use span, which finds the prefix satisfying a certain predicate function and also returns the remaining elements.
concat1 [] = []
concat1 (e : es)
| isDigit e = let (d, es') = span isDigit (e : es) in d : concat1 es'
| otherwise = [ e ] : concat1 es
Then, trying it out at GHCi:
ghci> concat1 ['1','5','+','2','4']
["15","+","24"]
An idea might be to construct a more generic function: a groupWith :: Eq b => (a -> b) -> [a] -> [(b,[a])] function like the one that is defined in Python's itertools:
groupWith :: Eq b => (a -> b) -> [a] -> [(b,[a])]
groupWith f = steps . map ((,) =<< f)
where steps [] = []
steps ((b,a):xs) = (b,(a : map snd ys)) : steps zs
where (ys,zs) = span ((b == ) . fst) xs
Given a function f :: a -> b and a list xs, it will construct groups [(b,[a])] such that every group represents the longest possible sequence of xs where f x is the same. So for groupWith isDigit "15+24", we get:
*Main Data.Char> groupWith isDigit ['1','5','+','2','4']
[(True,"15"),(False,"+"),(True,"24")]
Now we can simply obtain the second element snd of every tuple, so:
*Main Data.Char> map snd $ groupWith isDigit ['1','5','+','2','4']
["15","+","24"]
We can easily reuse this piece of code if we for instance wish to discriminate based on more conditions.
You can use groupBy in order to group together adjacent elements in a list over some equivalence function. You can use is like this:
import Data.List (groupBy)
import Data.Function (on)
import Data.Char (isDigit)
groupDigits :: String -> [String]
groupDigits = groupBy ((&&) `on` isDigit)
Prelude Data.List Data.Function Data.Char> groupDigits ['1','5','+','2','4']
["15","+","24"]
I guess as #4castle mentioned groupBy is the ideal tool for this job however my approach would be slightly different.
import Data.List (groupBy)
import Data.Function (on)
groupDigits :: String -> [String]
groupDigits = groupBy ((==) `on` ((&&) <$> (>'/') <*> (<':')))
*Main> groupDigits ['1','5','+','2','4']
["15","+","24"]
*Main> groupDigits ['1','5','+','+','2','4']
["15","++","24"]
The difference is instead of using (&&) operator i use an XNOR (which is simply (==) in Haskell).
And also my implementation of isDigit :: Char -> Bool is a little different than it is in Data.Char.

Haskell: change all indices from a list to some value

If I am given a list of objects and another list for some indices from this list, is there an easy way to change every object in this list with an index from the list of indices to a different value?
E.g. I am hoping there exists some function f such that
f 0 [4,2,5] [6,5,8,4,3,6,2,7]
would output
[6,5,0,4,0,0,2,7]
Here is a beautiful version that uses lens:
import Control.Lens
f :: a -> [Int] -> [a] -> [a]
f x is = elements (`elem` is) .~ x
Here is an efficient version that doesn't have any dependencies other than base. Basically, we start by sorting (and removing duplicates from the) indices list. That way, we don't need to scan the whole list for every replacement.
import Data.List
f :: a -> [Int] -> [a] -> [a]
f x is xs = snd $ mapAccumR go is' (zip xs [1..])
where
is' = map head . group . sort $ is
go [] (y,_) = ([],y)
go (i:is) (y,j) = if i == j then (is,x) else (i:is,y)
You can define a helper function to replace a single value and then use it to fold over your list.
replaceAll :: a -> [Int] -> [a] -> [a]
replaceAll repVal indices values = foldl (replaceValue repVal) values indices
where replaceValue val vals index = (take index vals) ++ [val] ++ (drop (index + 1) vals)
Sort the indices first. Then you can traverse the two lists in tandem.
{-# LANGUAGE ScopedTypeVariables #-}
import Prelude (Eq, Enum, Num, Ord, snd, (==), (<$>))
import Data.List (head, group, sort, zip)
f :: forall a. (Eq a, Enum a, Num a, Ord a) => a -> [a] -> [a] -> [a]
f replacement indices values =
go (head <$> group (sort indices)) (zip [0..] values)
where
go :: [a] -> [(a, a)] -> [a]
go [] vs = snd <$> vs
go _ [] = []
go (i:is) ((i', v):vs) | i == i' = replacement : go is vs
go is (v:vs) = snd v : go is vs
The sorting incurs an extra log factor on the length of the index list, but the rest is linear.

How to filter a list by another list in Haskell?

Suppose I have two lists A and B of the same length. I want to keep elements in A which are greater than corresponding elements in B. Let A=[1,5,8], B=[2,4,9], the result should be [5] because 1<2, 5>4, 8<9.
I come up with a solution. Let C=zip A B, then filter C, finally get result by taking fst of each element in C. It's not so elegant. Is there a simpler way?
Code:
map fst (filter (\ x-> (fst x) > (snd x)) (zip a b))
Your described solution looks fine to me.
An alternative which is not necessarily better:
import Data.Maybe
import Control.Monad
catMaybes $ zipWith (\a b -> guard (a>b) >> return a) list1 list2
According to the desugaring of monad comprehensions this should also work
{-# LANGUAGE MonadComprehensions #-}
[ a | ( a <- list1 | b <- list2 ), a > b ]
... but in practice it does not. It is a pity because I find it quite elegant.
I wonder whether I got it wrong or it is a GHC bug.
I was working on something similar and as a newbie this is the best I came up with:
filterGreaterThan xs ys = do (x,y) <- zip xs ys
guard (x > y)
return x
This solution is easier to reason about than the others. The do notation really shines here.
I'm not sure how your code looks but the following function look quite elegant to me:
greater :: Ord a => [a] -> [a] -> [a]
greater xs = map fst . filter ((>) <$> fst <*> snd) . zip xs
example :: [Int]
example = greater [1,5,8] [2,4,9] -- result is [5]
This pattern is well known in the Lisp community as the decorate-process-undecorate pattern.
A recursive approach, not so elegant as (any) of the other approaches, this relies on no explicit zipping and we get the result in one pass,
greater :: Ord a => [a] -> [a] -> [a]
greater [] [] = []
greater (x:xs) (y:ys)
| x > y = x : greater xs ys
| otherwise = greater xs ys
If you want to generalize this idea nicely, I would recommend looking to mapMaybe:
mapMaybe
:: (a -> Maybe b)
-> [a] -> [b]
Applying that idea to zipWith yields
zipWithMaybe
:: (a -> b -> Maybe c)
-> [a] -> [b] -> [c]
zipWithMaybe f xs ys =
[c | Just c <- zipWith f xs ys]
Now you can write your function
keepGreater :: Ord a => [a] -> [a] -> [a]
keepGreater = zipWithMaybe $
\x y -> x <$ guard (x > y)
Is it really worth the trouble? For lists, probably not. But something like this turns out to be useful in the context of merges for Data.Map.
Pretty similar to #chi's solution with Lists concant:
concat $ zipWith (\a b -> last $ []:[[a] | a > b]) as bs

Function to show the lowest represented element in a list

If you have a list such as this in Haskell:
data TestType = A | B | C deriving (Ord, Eq, Show)
List1 :: [TestType]
List1 = [A,B,C,B,C,A,B,C,C,C]
Is it possible to write a function to determin which element is represented the least in a list (so in this case 'A')
My initial thought was to write a helper function such as this but now I am not sure if this is the right approach:
appears :: TestType -> [TestType] -> Int
appears _ [] = 0
appears x (y:ys) | x==y = 1 + (appears x ys)
| otherwise = appears x ys
I am still fairly new to Haskell, so apologies for the potentially silly question.
Many thanks
Slightly alternative version to Matt's approach
import Data.List
import Data.Ord
leastFrequent :: Ord a => [a] -> a
leastFrequent = head . minimumBy (comparing length) . group . sort
You can build a map counting how often each item occurs in the list
import qualified Data.Map as Map
frequencies list = Map.fromListWith (+) $ zip list (repeat 1)
Then you can find the least/most represented using minimumBy or maximumBy from Data.List on the list of Map.assocs of the frequency map, or even sort it by frequency using sortBy.
module Frequencies where
import Data.Ord
import Data.List
import qualified Data.Map as Map
frequencyMap :: Ord a => [a] -> Map.Map a Int
frequencyMap list = Map.fromListWith (+) $ zip list (repeat 1)
-- Caution: leastFrequent will cause an error if called on an empty list!
leastFrequent :: Ord a => [a] -> a
leastFrequent = fst . minimumBy (comparing snd) . Map.assocs . frequencyMap
ascendingFrequencies :: Ord a => [a] -> [(a,Int)]
ascendingFrequencies = sortBy (comparing snd) . Map.assocs . frequencyMap
Here's another way to do it:
sort the list
group the list
find the length of each group
return the group with the shortest length
Example:
import GHC.Exts
import Data.List
fewest :: (Eq a) => [a] -> a
fewest xs = fst $ head sortedGroups
where
sortedGroups = sortWith snd $ zip (map head groups) (map length groups)
groups = group $ sort xs
A less elegant idea would be:
At first sort and group the list
then pairing the cases with their number of representations
at last sort them relative to their num of representations
In code this looks like
import Data.List
sortByRepr :: (Ord a) => [a] ->[(a,Int)]
sortByRepr xx = sortBy compareSnd $ map numOfRepres $ group $ sort xx
where compareSnd x y = compare (snd x) (snd y)
numOfRepres x = (head x, length x)
the least you get by applying head to the resulting list.

Resources