I have a list with some sublists and I need to order it by length.
For example:
[[1,3,4,9],[2,4],[5,4,7]] would become [[2,4],[5,4,7],[1,3,4,9]].
You can make use of sortOn :: Ord b => (a -> b) -> [a] -> [a] to sort items in a list based on the result of a function called on the elements, for example:
Prelude> import Data.List(sortOn)
Prelude Data.List> sortOn length [[1,3,4,9],[2,4],[5,4,7]]
[[2,4],[5,4,7],[1,3,4,9]]
You can use comparing to generate a custom comparison function with the length function, the sort the list with the builtin sortBy function:
import Data.List
import Data.Ord
x :: [[Int]]
x = sortBy (comparing length) [[1,3,4,9],[2,4],[5,4,7]]
-- x == [[2,4],[5,4,7],[1,3,4,9]]
Related
The goal is to find the Longest Increasing Subsequence (LIS) of a list in Haskell. I tried to run the following code, but the error of couldn't find modules appeared. I saw answers to This question and I understand that the ordered package is old and not used anymore.
import Data.Ord ( comparing )
import Data.List ( maximumBy, subsequences )
import Data.List.Ordered ( isSorted, nub )
lis :: Ord a => [a] -> [a]
lis = maximumBy (comparing length) . map nub . filter isSorted . subsequences
-- longest <-- unique <-- increasing <-- all
main = do
print $ lis [3,2,6,4,5,1]
print $ lis [0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15]
print $ lis [1,1,1,1]
Therefore, I tried to use only:
import Data.List
but I got the following error :
main.hs:3:18: error:
Variable not in scope:
comparing :: (t0 a0 -> Int) -> [a] -> [a] -> Ordering
|
3 | lis = maximumBy (comparing length) . map nub . filter isSorted . subsequences
| ^^^^^^^^^
main.hs:3:56: error: Variable not in scope: isSorted :: [a] -> Bool
|
3 | lis = maximumBy (comparing length) . map nub . filter isSorted . subsequences
| ^^^^^^^^
exit status 1
nub is now in Data.List. If an isSorted function is available in any normal library, Hoogle doesn't show it. You can easily write one yourself, though I haven't given much thought to whether the following suggestion is the most efficient implementation - and it probably doesn't work with infinite lists (I think that the answer to both questions is no):
isSorted :: Ord a => [a] -> Bool
isSorted l = sort l == l
(Using sort from Data.List.)
With these imports:
import Data.Ord (comparing)
import Data.List (maximumBy, subsequences, nub, sort)
the lis function now compiles.
This is a function that produces an infinite list of random numbers
import System.Random
values :: [Int]
values = map fst $ scanl (\(r, gen) _ -> randomR (1,10) gen) (randomR (1,10) (mkStdGen 1)) $ repeat ()
I want to reduce sequences for duplicate elements into one element e.g
[2,3,4,1,7,7,7,3,4,1,1,1,3,..] -> [2,3,4,1,7,3,4,1,3,..]
So, I need some elegant function "f" from [Int] -> [Int] that do this.
Also, it must work with an infinite list lazily, so if I run
f values
it must not hang and output data in real-time
You can work with group :: Eq a => [a] -> [[a]] to make a list of groups. So for the given sample data, this will generate:
Prelude> import Data.List(group)
Prelude Data.List> group [2,3,4,1,7,7,7,3,4,1,1,1,3]
[[2],[3],[4],[1],[7,7,7],[3],[4],[1,1,1],[3]]
Then we can for each sublist only yield the first element with head, we know that such element exists, since otherwise it would never have constructed a new group in the first place:
Prelude Data.List> map head (group [2,3,4,1,7,7,7,3,4,1,1,1,3])
[2,3,4,1,7,3,4,1,3]
This thus means that you can define f as:
import Data.List(group)
f :: Eq a => [a] -> [a]
f = map head . group
This works on infinite lists as well. For example if we end the list with an infinite list of 5s, then it processes the list until that five and keeps looking for a new value:
Prelude Data.List> map head (group (2 : 3 : 4 : 1 : 7 : 7 : 7 : 3 : 4 : 1 : 1 : 1 : 3 : repeat 5))
[2,3,4,1,7,3,4,1,3,5
or we can make use of the group :: (Foldable f, Eq a) => f a -> [NonEmpty a] of Data.List.NonEmpty:
import Data.List.NonEmpty(group)
import qualified Data.List.NonEmpty as NE
f :: Eq a => [a] -> [a]
f = map NE.head . group
my question is how to implement this:
import Data.Char
import Data.List
freq :: [String] -> [(String ,Int)]
freq words = []
in Haskell. I want to count how many times a specific String occurs in a list of Strings.
The bare bones ways to do this is to:
Sort the list
Accumulate consecutive equal elements into groups.
Count the length of each group.
The functions used are sort and group from Data.List:
sort :: Ord a => [a] -> [a]
group :: Eq a => [a] -> [[a]]
An example of how group works:
group [1,1,1,2,3,3,4] -> [ [1,1,1], [2], [3,3], [4] ]
So now you have to turn a group of equal elements like [1,1,1] into the tuple (1,3). I'll leave that for you to figure out.
The complete definition for freq will look like:
freq :: [String] -> [ (String,Int) ]
freq xs = map pair (group ( sort xs ))
where pair = ...(your definition here)...
As said in the comments, using Data.Map :
freq :: [String] -> [(String ,Int)]
freq words = toList $ fromListWith (+) [(w, 1) | w <- words]
https://www.haskell.org/hoogle might be your friend. You might like to use a function that has the type signature [a] -> a -> Int. After hoogeling you will immediately find:
elemIndices :: Eq a => a -> [a] -> [Int]
base Data.List
The elemIndices function extends elemIndex, by returning the indices of all elements equal to the query element, in ascending order.
Can u help me with this code .i want to extract the tutor which is the last element in the
each tuple and use it to sort the entire list.
import Data.List
type CourseData = [(String,String,String,String,String)]
l :: CourseData
--list contains name of student, year, programme and personal tutor
l = [("fondi","201202378","2012","Bsc280"," tautology"),
("fondi","201202378","2012","Bsc280"," tautology"),
("Sylvee","200801245","2008","Bsc209","puma"),
("dijeje","201307845","2013","Bsc205","tautology"),
("heron","201002567","2010","Bsc280","setlhako"),
("slow","201198746","2011","Bsc205"," mampu"),
("Sylvee","201198746","2008","bsc209"," puma"),
("Sylvee","201198746","2008","bsc209"," puma")]
sortByTutor :: CourseData ->String -> [String]
sortByTutor list =sort[tutor|(name,id,year,prog,tutor)<-list ]
when i use the above method ,it only returns the sorted list of tutors .what can i change so that it returns the whole list sorted according to the tutor name?
You can try sortBy from Data.List:
sortBy (\(_,_,_,_,t1) (_,_,_,_,t) -> compare t1 t) l
What Ankur said, use sortBy. Here is a slightly different way of writing this sort:
import Data.List (sortBy)
import Data.Function (on)
sortByTutor xs = sortBy (compare `on` \(_,_,_,_,t) -> t) xs
This is useful if you have accessor functions that extract the fields from the tuples, e.g. for tutor:
tutor (_,_,_,_,t) = t
Then you can simply reuse them:
sortByTutor xs = sortBy (compare `on` tutor) xs
which is very readable.
Given a list of tuples like this:
dic = [(1,"aa"),(1,"cc"),(2,"aa"),(3,"ff"),(3,"gg"),(1,"bb")]
How to group items of dic resulting in a list grp where,
grp = [(1,["aa","bb","cc"]), (2, ["aa"]), (3, ["ff","gg"])]
I'm actually a newcomer to Haskell...and seems to be falling in love with it..
Using group or groupBy in Data.List will only group similar adjacent items in a list.
I wrote an inefficient function for this, but it results in memory failures as I need to process a very large coded string list. Hope you would help me find a more efficient way.
Whenever possible, reuse library code.
import Data.Map
sortAndGroup assocs = fromListWith (++) [(k, [v]) | (k, v) <- assocs]
Try it out in ghci:
*Main> sortAndGroup [(1,"aa"),(1,"cc"),(2,"aa"),(3,"ff"),(3,"gg"),(1,"bb")]
fromList [(1,["bb","cc","aa"]),(2,["aa"]),(3,["gg","ff"])]
EDIT In the comments, some folks are worried about whether (++) or flip (++) is the right choice. The documentation doesn't say which way things get associated; you can find out by experimenting, or you can sidestep the whole issue using difference lists:
sortAndGroup assocs = ($[]) <$> fromListWith (.) [(k, (v:)) | (k, v) <- assocs]
-- OR
sortAndGroup = fmap ($[]) . M.fromListWith (.) . map (fmap (:))
These alternatives are about the same length as the original, but they're a bit less readable to me.
Here's my solution:
import Data.Function (on)
import Data.List (sortBy, groupBy)
import Data.Ord (comparing)
myGroup :: (Eq a, Ord a) => [(a, b)] -> [(a, [b])]
myGroup = map (\l -> (fst . head $ l, map snd l)) . groupBy ((==) `on` fst)
. sortBy (comparing fst)
This works by first sorting the list with sortBy:
[(1,"aa"),(1,"cc"),(2,"aa"),(3,"ff"),(3,"gg"),(1,"bb")]
=> [(1,"aa"),(1,"bb"),(1,"cc"),(2,"aa"),(3,"ff"),(3,"gg")]
then grouping the list elements by the associated key with groupBy:
[(1,"aa"),(1,"bb"),(1,"cc"),(2,"aa"),(3,"ff"),(3,"gg")]
=> [[(1,"aa"),(1,"bb"),(1,"cc")],[(2,"aa")],[(3,"ff"),(3,"gg")]]
and then transforming the grouped items to tuples with map:
[[(1,"aa"),(1,"bb"),(1,"cc")],[(2,"aa")],[(3,"ff"),(3,"gg")]]
=> [(1,["aa","bb","cc"]), (2, ["aa"]), (3, ["ff","gg"])]`)
Testing:
> myGroup dic
[(1,["aa","bb","cc"]),(2,["aa"]),(3,["ff","gg"])]
Also you can use TransformListComp extension, for example:
Prelude> :set -XTransformListComp
Prelude> import GHC.Exts (groupWith, the)
Prelude GHC.Exts> let dic = [ (1, "aa"), (1, "bb"), (1, "cc") , (2, "aa"), (3, "ff"), (3, "gg")]
Prelude GHC.Exts> [(the key, value) | (key, value) <- dic, then group by key using groupWith]
[(1,["aa","bb","cc"]),(2,["aa"]),(3,["ff","gg"])]
If the list is not sorted on the first element, I don't think you can do better than O(nlog(n)).
One simple way would be to just sort and then use anything from the answer of second part.
You can use from Data.Map a map like Map k [a] to use first element of tuple as key and keep on adding to the values.
You can write your own complex function, which even after you all the attempts will still take O(nlog(n)).
If list is sorted on the first element as is the case in your example, then the task is trivial for something like groupBy as given in the answer by #Mikhail or use foldr and there are numerous other ways.
An example of using foldr is here:
grp :: Eq a => [(a,b)] -> [(a,[b])]
grp = foldr f []
where
f (z,s) [] = [(z,[s])]
f (z,s) a#((x,y):xs) | x == z = (x,s:y):xs
| otherwise = (z,[s]):a
{-# LANGUAGE TransformListComp #-}
import GHC.Exts
import Data.List
import Data.Function (on)
process :: [(Integer, String)] -> [(Integer, [String])]
process list = [(the a, b) | let info = [ (x, y) | (x, y) <- list, then sortWith by y ], (a, b) <- info, then group by a using groupWith]