Haskell - Remove n smallest elements in a list of tuples - list

I've got the following code that takes an int value and removes the first n amount of elements in a list.
removeEle :: Int -> [a] -> [a]
removeEle n xs
| ((n <= 0) || null xs) = xs
| otherwise = removeEle (n-1) (tail xs)
How would i append this so that this works on a list of tuples by their second element? etc
[(String1, 50)], [(String2, 600)], [(String3, 10)]

There is not much you can do to amend your current solution so that it removes the first n smallest elements. To be able to remove the first n smallest, you need to have the total ordering of the whole list so that you can decide which elements are in the n smallest interval.
One easy solution is to sort the list and the remove the first n elements. This solution doesn't preserve the original ordering though.
Using soryBy and drop from Data.List you can do the following:
removeNSmallest :: Ord a => Int -> [(String, a)] -> [(String, a)]
removeNSmallest n xs = drop n $ sortBy (\(_, a) (_, b) -> compare a b) xs
As #Micha Wiedenmann pointed out, you can use sortBy (comparing snd) for sorting the tuples.
A small test:
λ> removeNSmallest 1 [("String1", 50), ("String2", 600), ("String3", 10)]
[("String1",50),("String2",600)]
To preserve the original ordering, one solution is to create a separate ordered list of the second elements of the tuple. Then traverse the original list and for each element that is in the ordered list, remove one from the original.
Your original solution for removing the first n elements of a list would be much more readable if you wrote it using drop:
removeEle :: Int -> [a] -> [a]
removeEle n xs = drop n xs
Or if you want to use explicit recursion:
removeEle :: Int -> [a] -> [a]
removeEle _ [] = []
removeEle 0 xs = xs
removeEle n x:xs = removeEle (n-1) xs

Related

Function to find number of occurrences in list

So I already have a function that finds the number of occurrences in a list using maps.
occur :: [a] -> Map a a
occur xs = fromListWith (+) [(x, 1) | x <- xs]
For example if a list [1,1,2,3,3] is inputted, the code will output [(1,2),(2,1),(3,2)], and for a list [1,2,1,1] the output would be [(1,3),(2,1)].
I was wondering if there's any way I can change this function to use foldr instead to eliminate the use of maps.
You can make use of foldr where the accumulator is a list of key-value pairs. Each "step" we look if the list already contains a 2-tuple for the given element. If that is the case, we increment the corresponding value. If the item x does not yet exists, we add (x, 1) to that list.
Our function thus will look like:
occur :: Eq => [a] -> [(a, Int)]
occur = foldr incMap []
where incMap thus takes an item x and a list of 2-tuples. We can make use of recursion here to update the "map" with:
incMap :: Eq a => a -> [(a, Int)] -> [(a, Int)]
incMap x = go
where go [] = [(x, 1)]
go (y2#(y, ny): ys)
| x == y = … : ys
| otherwise = y2 : …
where I leave implementing the … parts as an exercise.
This algorithm is not very efficient, since it takes O(n) to increment the map with n the number of 2-tuples in the map. You can also implement incrementing the Map for the given item by using insertWith :: Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a, which is more efficient.

Rearrange/sort list by largest, smallest, second largest, second smallest etc

Given an array of integers, how can I sort them by : largest-smallest-2nd largest - 2nd smallest?
I'm trying to :
- Duplicate and sort an array in order ascending and descending
- Create the sorted array by picking the head of each arrays describes as above
I am not familiar with Haskell programming but here's what I've done
sort :: [Int] -> [Int]
sort [] = []
sort (x:xs) = sort smaller ++ [x] ++ sort larger
where
smaller = filter (<= x) xs
larger = filter (> x) xs
wave :: [Int] -> [Int]
wave [] = []
wave [x] = [x]
wave (x:xs) = if length (x:xs)>1
then :
ascending = sort (x:xs)
descending = reverse (ascending)
iterator = length(x:xs)
if iterator > 0 && (length(ascending)==0 || length(descending)==0)
then do wave(x:xs) = head(descending) + head(ascending)
tail(descending)
tail(ascending)
Thanks by advance for your help
frontEndSort consumes a list xs, it sorts its elements in descending order. Next, pair each element in xs with element from the same list but in ascending order. Convert each pair to a list then flatten the whole list. Finally, we take as many elements as in xs.
frontEndSort :: [Int] -> [Int]
frontEndSort xs = take (length xs) $ do
(x, y) <- zip <$> sortBy (comparing Down) <*> sort $ xs
[x, y]
braid function intercalates two list elem by elem. We next apply braid to the list ordered in ascending and descending. Finally, since we end up with the orginal list duplicated, we take just the length of the original list.
braid :: [Int] -> [Int] -> [Int]
braid [] as = as
braid ds [] = ds
braid (d:ds) (a:as) = d:a:braid ds as
wave :: [Int] -> [Int]
wave xs = take (length xs) braided
where asc = sort xs
desc = reverse asc
braided = braid desc asc
Benchmark Edit:
despite of the fact that I think my implementation is easier to understand for haskell beginers, I got to say that after having benckmarked my solution against ƛƛƛ's solution, mine is ~ 4 to 7 times slower than his/her.
For One hundred thousand length list:
mine: 211 ms
ƛƛƛ's: 53 ms
For One million length list:
mine: 3.8 sec
ƛƛƛ's: 547 ms
Edit Two: Don't use reverse
Replacing desc = reverse asc by desc = sortOn Down xs produces same speed program as ƛƛƛ's applicative solution and willness comprehension list implementation.
Another way to use the zipping:
import Data.Ord
frontEndSort :: [Int] -> [Int]
frontEndSort xs =
zipWith (flip const) xs
( concat . getZipList . traverse ZipList
$ [sortBy (comparing Down) xs, sort xs] )
Here traverse ZipList :: [[b]] -> ZipList [b] so it already produces the pairs as lists, not tuples.

haskell: how to get list of numbers which are higher then their neighbours in a starting list

I am trying to learn Haskell and I want to solve one task. I have a list of Integers and I need to add them to another list if they are bigger then both of their neighbors. For Example:
I have a starting list of [0,1,5,2,3,7,8,4] and I need to print out a list which is [5, 8]
This is the code I came up but it returns an empty list:
largest :: [Integer]->[Integer]
largest n
| head n > head (tail n) = head n : largest (tail n)
| otherwise = largest (tail n)
I would solve this as outlined by Thomas M. DuBuisson. Since we want the ends of the list to "count", we'll add negative infinities to each end before creating triples. The monoid-extras package provides a suitable type for this.
import Data.Monoid.Inf
pad :: [a] -> [NegInf a]
pad xs = [negInfty] ++ map negFinite xs ++ [negInfty]
triples :: [a] -> [(a, a, a)]
triples (x:rest#(y:z:_)) = (x,y,z) : triples rest
triples _ = []
isBig :: Ord a => (a,a,a) -> Bool
isBig (x,y,z) = y > x && y > z
scnd :: (a, b, c) -> b
scnd (a, b, c) = b
finites :: [Inf p a] -> [a]
finites xs = [x | Finite x <- xs]
largest :: Ord a => [a] -> [a]
largest = id
. finites
. map scnd
. filter isBig
. triples
. pad
It seems to be working appropriately; in ghci:
> largest [0,1,5,2,3,7,8,4]
[5,8]
> largest [10,1,10]
[10,10]
> largest [3]
[3]
> largest []
[]
You might also consider merging finites, map scnd, and filter isBig in a single list comprehension (then eliminating the definitions of finites, scnd, and isBig):
largest :: Ord a => [a] -> [a]
largest xs = [x | (a, b#(Finite x), c) <- triples (pad xs), a < b, c < b]
But I like the decomposed version better; the finites, scnd, and isBig functions may turn out to be useful elsewhere in your development, especially if you plan to build a few variants of this for different needs.
One thing you might try is lookahead. (Thomas M. DuBuisson suggested a different one that will also work if you handle the final one or two elements correctly.) Since it sounds like this is a problem you want to solve on your own as a learning exercise, I’ll write a skeleton that you can take as a starting-point if you want:
largest :: [Integer] -> [Integer]
largest [] = _
largest [x] = _ -- What should this return?
largest [x1,x2] | x1 > x2 = _
| x1 < x2 = _
| otherwise = _
largest [x1,x2,x3] | x2 > x1 && x2 > x3 = _
| x3 > x2 = _
| otherwise = _
largest (x1:x2:x3:xs) | x2 > x1 && x2 > x3 = _
| otherwise = _
We need the special case of [x1,x2,x3] in addition to (x1:x2:x3:[]) because, according to the clarification in your comment, largest [3,3,2] should return []. but largest [3,2] should return [3]. Therefore, the final three elements require special handling and cannot simply recurse on the final two.
If you also want the result to include the head of the list if it is greater than the second element, you’d make this a helper function and your largest would be something like largest (x1:x2:xs) = (if x1>x2 then [x1] else []) ++ largest' (x1:x2:xs). That is, you want some special handling for the first elements of the original list, which you don’t want to apply to all the sublists when you recurse.
As suggested in the comments, one approach would be to first group the list into tuples of length 3 using Preludes zip3 and tail:
*Main> let xs = [0,1,5,2,3,7,8,4]
*Main> zip3 xs (tail xs) (tail (tail xs))
[(0,1,5),(1,5,2),(5,2,3),(2,3,7),(3,7,8),(7,8,4)]
Which is of type: [a] -> [b] -> [c] -> [(a, b, c)] and [a] -> [a] respectively.
Next you need to find a way to filter out the tuples where the middle element is bigger than the first and last element. One way would be to use Preludes filter function:
*Main> let xs = [(0,1,5),(1,5,2),(5,2,3),(2,3,7),(3,7,8),(7,8,4)]
*Main> filter (\(a, b, c) -> b > a && b > c) xs
[(1,5,2),(7,8,4)]
Which is of type: (a -> Bool) -> [a] -> [a]. This filters out elements of a list based on a Boolean returned from the predicate passed.
Now for the final part, you need to extract the middle element from the filtered tuples above. You can do this easily with Preludes map function:
*Main> let xs = [(1,5,2),(7,8,4)]
*Main> map (\(_, x, _) -> x) xs
[5,8]
Which is of type: (a -> b) -> [a] -> [b]. This function maps elements from a list of type a to b.
The above code stitched together would look like this:
largest :: (Ord a) => [a] -> [a]
largest xs = map (\(_, x, _) -> x) $ filter (\(a, b, c) -> b > a && b > c) $ zip3 xs (tail xs) (tail (tail xs))
Note here I used typeclass Ord, since the above code needs to compare with > and <. It's fine to keep it as Integer here though.

Selecting string elements in a list using integer elements from another list

I'm going to use an example to explain my question because I'm not sure the best way to put it into words.
Lets say I have two lists a and b:
a = ["car", "bike", "train"] and b = [1, 3]
And I want to create a new list c by selecting the items in a whose positions correspond to the integers in b, so list c = ["car", "train"]
How would I do this in Haskell? I think I have to use list comprehension but am unsure how. Cheers.
The straightfoward way to do this is using the (!!) :: [a] -> Int -> a operator that, for a given list and zero-based index, gives the i-th element.
So you could do this with the following list comprehension:
filterIndex :: [a] -> [Int] -> [a]
filterIndex a b = [a!!(i-1) | i <- b]
However this is not efficient since (!!) runs in O(k) with k the index. Usually if you work with lists you try to prevent looking up the i-th index.
In case it is guaranteed that b is sorted, you can make it more efficient with:
-- Only if b is guaranteed to be sorted
filterIndex = filterIndex' 1
where filterIndex' _ _ [] = []
filterIndex' i a:as2 js#(j:js2) | i == j = a : tl js2
| otherwise = tl js
where tl = filterIndex' (i+1) as2
Or even more efficient:
-- Only if b is guaranteed to be sorted
filterIndex = filterIndex' 1
where filterIndex' i l (j:js) | (a:as) <- drop (j-i) l = a : filterIndex' (j+1) as (js)
filterIndex' _ _ [] = []
I am going to assume you're using b = [0, 2] instead (lists are 0 indexed in Haskell).
You can use a fold to build the new list:
selectIndices :: [a] -> [Int] -> [a]
selectIndices as is = foldr (\i bs -> as !! i : bs) [] is
This starts with an empty list and adds new elements by selecting them from the list of as using an index i from the list of indices is.
More advanced: if you prefer a point-free style, the same function can be written:
selectIndices :: [a] -> [Int] -> [a]
selectIndices as = foldr ((:) . (as !!)) []
Another approach which could be more efficient if the indices are sorted would be to go through the list one element at a time while keeping track of the current index:
selectIndices :: [a] -> [Int] -> [a]
selectIndices as is = go as 0 (sort is)
where
go :: [a] -> Int -> [Int] -> [a]
go [] _ _ = []
go _ _ [] = []
go (a:as) n (i:is)
| n == i = a : go as (n + 1) is
| otherwise = go as (n + 1) (i:is)
A simple approach is tagging the values in a with the indices and then filtering according to the indices:
filterIndex :: [Int] -> [a] -> [a]
filterIndex b = fmap snd . filter (\(i, _) -> i `elem` b) . zip [1..]
-- non-point-free version:
-- filterIndex b a = fmap snd (filter (\(i, _) -> i `elem` b) (zip [1..] a))
(If you want zero-based rather than one-based indexing, just change the infinite list to [0..]. You can even parameterise it with something like [initial..].)
If you need to make this more efficient, you might consider, among other things, a filtering algorithm that exploits ordering in b (cf. the answers by Boomerang and Willem Van Onsem), and building a dictionary from the zip [1..] a list of pairs.

Shuffling a List Based On an Int List

Given the code:
data Error a = Fail|Ok a
deriving (Eq, Ord, Show)
split :: Int -> [a] -> (Error ([a],[a]))
split 0 list = Ok ([], list)
split n list
| n < 0 = Fail
| n > length (list) = Fail
| otherwise = Ok (take n list, drop n list)
interleave :: [a] -> [a] -> [a]
interleave list [] = list
interleave [] list = list
interleave (x:xs) (y:ys) = x : y : interleave xs ys
shuffle :: [Int] -> [a] -> Error [a]
How I write the function shuffle which will take a list of Ints, and split another list based on those ints. Examples of the int list would be intList = [20,23,24,13] where shuffle will split a list after the 20th element, interleave, split after the 23rd element, interleave, and so on.
Okay, what you want is basically the following:
Given a list xs and indices [a1, a2, a3, ..], split xs at a1, interleave, split it at a2 and interleave, and so on...
Now that leaves us with two functions:
step :: Int -> [a] -> [a]
step index xs = ??? -- something with split and interleave
shuffle :: [a]
shuffle [] xs = xs
shuffle (i:indices) xs = let newList = step i xs
in ??? -- something with recursion
Try to write the rest of these functions on yourself.
step can easily be expressed as let (x1, x2) = split index xs in interleave x1 x2. Basically, the rest of shuffle can be written as shuffle indices newList.
I figured it out:
shuffle [] xs = Ok (xs)
shuffle (x:xs) list = case (split x list) of
Fail -> Fail
Ok (l1, l2) -> shuffle xs (interleave l1 l2)