Let lst be a List with tuples which I want to reverse each (The order of the tuples needs to be the same). For example:
[(a,b);(c,d)] -> [(b,a);(d,c)]
I know that it can be done with map:
List.map (fun (a,b) -> (b,a)) [(1,2);(3,4)];;
- : (int * int) list = [(2, 1); (4, 3)]
But I´m looking for a way to achieve it with List.fold_left. My approach is to match the list with [] as a accumulator to concatenate every reversed tuple together, but I keep getting type-Errors:
List.fold_left (fun (a,b) -> (b,a)) [] lst;;
List.fold_left takes three arguments:
A function of type 'a -> 'b -> 'a
An accumulator of type 'a
A list of type 'b list
Your function (fun (a,b) -> (b,a)) is missing an argument, the accumulator, on which you want to concatenate the reversed pairs
(fun acc (a,b) -> (b,a) :: acc)
Both the answer by #Lhooq and #rithvik are mostly spot-on, but will reverse the order of the tuples in the resulting list.
We either need to feed the result to List.rev or use List.fold_right.
utop # List.fold_left (fun acc (a, b) -> (b, a) :: acc) [] [(1, 2); (3, 4)] |> List.rev;;
- : (int * int) list = [(2, 1); (4, 3)]
utop # List.fold_right (fun (a, b) acc -> (b, a) :: acc) [(1, 2); (3, 4)] [];;
- : (int * int) list = [(2, 1); (4, 3)]
Using List.map seems like a natural option here, because you could do something like:
List.map (fun (a, b) -> (b, a)) lst
But if you wanted to use List.fold_left then you need to reverse each pair and then cons it to the accumulator list:
List.fold_left (fun acc (a, b) -> (b, a)::acc) [] lst
Since fold_left takes the following function signature: ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a, you need to make sure that your first argument is a function that takes in an accumulator list and an individual list element (in this case a tuple), and then returns a list.
EDIT: #Chris rightly pointed out that with this solution the order of the tuples themselves would also flip. You can fix this by wrapping the function with List.rev, or instead of cons-ing you can append the tuple to the end of the list:
List.fold_left (fun acc (a, b) -> acc#[(b, a)]) [] lst
Related
So far, I've made a function which matches all elements of one list with only the first element of another list, but I need it to match all elements of list 1 with all elements of list 2.
My code so far looks like this:
let prototype (lst1: 'a list) (lst2: 'b list) =
List.map (fun i -> [i,lst2.Head]) lst1 |> List.concat
So you figured out how to pair all elements of lst1 with a single thing. Great!
Now look: inside the map's parameter, you have the exact same problem - pair every element of lst2 with i. So you can just solve it the exact same way:
let prototype (lst1: 'a list) (lst2: 'b list) =
List.map (fun i -> List.map (fun j -> [i, j]) lst2 |> List.concat) lst1 |> List.concat
But this is a bit ugly of course. There are a few minor modifications you can make to make it prettier.
First, note that List.map >> List.concat is equivalent to List.collect:
let prototype (lst1: 'a list) (lst2: 'b list) =
List.collect (fun i -> List.collect (fun j -> [i, j]) lst2) lst1
But of course a much better option is to use list comprehensions:
let prototype (lst1: 'a list) (lst2: 'b list) =
[ for i in lst1 do
for j in lst2 ->
i, j
]
My goal here was to convert a (int * int) list to an int list. This is what I did:
let tuples_list_to_list l =
let rec aux_tuples_to_list acc l =
match l with
| [] -> acc
| x :: tl -> aux_tuples_to_list (fst x :: snd x :: acc) tl in
aux_tuples_to_list [] l
I was wondering if there was a more "elegant" even though this is subjective or at least better, way to write my function. I was thinking about using List.map or List.fold_left but I was having issues figuring out I could use those two functions to do the same thing I did. Basically, I think it would be possible to have a one-liner instead of the whole function I wrote.
What do you think? Thanks
This task is suited for List.concat_map (also known as "flat map" in some other languages):
(* List.concat_map : ('a -> 'b list) -> 'a list -> 'b list *)
let tuples_list_to_list l =
List.concat_map (fun (x, y) -> [x; y]) l
You can use List.fold_left, but you'll have to reverse the result at the end as the list is constructed in reverse order:
let tuples_list_to_list l =
List.rev (List.fold_left (fun acc (x, y) -> y :: x :: acc) [] l)
You can also deconstruct the tuple values in the pattern matching instead of using fst and snd (This version, unlike yours, gives a result list with the numbers in the same order as the orignal):
let tuples_list_to_list l =
let rec aux_tuples_to_list acc l =
match l with
| [] -> List.rev acc
| (x, y) :: tl -> aux_tuples_to_list (y :: x :: acc) tl in
aux_tuples_to_list [] l
Yet Another Option is using List.fold_right, which avoids the need to reverse the accumulator list at the end at the cost of not being tail recursive:
let tuples_list_to_list l =
List.fold_right (fun (x, y) acc -> x :: y :: acc) l [];;
So, I am given a list containing tuples and I need to break it down into two lists, the first list containing the elements with odd index and the second list containing the elements with even index, must be done using fold, here is my attempt:
breakList :: [(Integer, Integer)] -> [[(Integer, Integer)]]
breakList [] = [[], []]
breakList xxs#(x:xs) = foldl (\ acc y -> if length (acc !! 0) < length (acc !! 1) then y : (acc !! 0) else y : (acc !! 1) ) [[], []] xxs
Error I am getting:
Couldn't match type '(Integer, Integer)'
with '[(Integer, Integer)]'
Expected type: [[(Integer, Integer)]]
when hovering over y : (acc !! 1) and y : (acc !! 0)
Example:
Input:
ex1 = [ (2, 2), (1, 3), (2, 3), (2, 4), (3, 5), (0, 2), (2, 1), (1, 4)
, (2, 0), (1, 2), (3, 1), (1, 0)]
Output
breakList ex1
== ( [(2,2),(2,3),(3,5),(2,1),(2,0),(3,1)] , [(1,3),(2,4),(0,2),(1,4),(1,2),(1,0)])
The standard trick here, as hinted at by Willem in the comments, which I first saw few years back on SO in an (F# or Ocaml) answer by [user:Ed'ka], is
evenodds :: [a] -> ([a], [a])
evenodds xs = foldr g ([],[]) xs
where
g x ~(as,bs) = (bs,x:as)
or
oddevens :: [a] -> ([a], [a])
oddevens xs = foldr g ([],[]) xs
where
g x ~(bs,as) = (x:as,bs)
What are odd positions from here, are even positions from the position one notch further on the list.
The tilde ~ introduces a lazy pattern so that the function is properly lazy in its operations.
Note that you want to split a list into two lists of a pair, so the return type should be
([(Integer, Integer)], [(Integer, Integer)])
not
[[(Integer, Integer)]]
and access the element of pair, you can use fst and snd instead of through index, and finally, use foldl will return the resulted list in reversed order, it can be fixed use foldr instead. The correction look like:
breakList :: [(Integer, Integer)]->([(Integer, Integer)], [(Integer, Integer)])
breakList xxs = foldr (\y acc-> if length (fst acc) < length (snd acc)
then (y:(fst acc), snd acc)
else (fst acc, y:(snd acc)) ) ([], []) xxs
I have this series of functions, isMember, addElem and countries:
let rec isMember x = function
| y::ys -> y=x || (isMember x ys)
| [] -> false
let addElem x ys = if isMember x ys then ys else x::ys
let rec countries = function
| [] -> []
| (c1,c2)::m -> addElem c1 (addElem c2 (countries m))
I want to rewrite countries using higher-order functions, but I'm not entirely sure how to:
My guess would be it having something to do with List.map, as I'm applying a function to each element of the list.
let countriesHigherOrder m =
List.map (fun x -> addElem x m)
Instead of using List.map, you can use List.fold with an accu that you initialize to [] and add elements to accu.
let countriesHigherOrder m =
List.fold (fun acc (c1,c2) -> addElem c1 (addElem c2 acc)) [] m
or by defining addPair:
let addPair (x, y) ys =
addElem x (addElem y ys)
let countriesHigherOrder m =
List.fold (fun acc (c1,c2) -> addPair (c1, c2) acc) [] m
If you want to flatten a list of pairs into a simple list and at the same time, preserve only one occurence of identical elements, the shortest code will involve the append operator.
let countries' m =
List.unzip m ||> (#)
|> Seq.distinct
|> Seq.toList
If, on the other hand, you need the peculiar order of your doubly recursive approach, you can convert the list of tuples into two-element lists and concatenate those.
let countries'' m =
List.rev m
|> List.collect(fun (x,y) -> [y;x])
|> Seq.distinct
|> Seq.toList
|> List.rev
I am trying to start learning haskell, and a question came up.
Say, I have a function
countFilter :: (a -> Bool) -> [a] -> ([a], Int)
countFilter a z = case z of [] -> ([], 0);
(x:xs) -> (filter a z , length (filter a z))
It returns a list, all the items of which apply to a certain predicate and a length of that list, which is not relevant.
countFilter (<7) [1,2,4,7,11,8,2] will output ([1,2,4,2], 4).
How to create such an output: ([7,11,8], 4) using the same predicate (<7)?
If I understand your question correctly, you want to return all the elements that don't match the predicate (< 7) as the first element of the pair.
In that case you can simply use the not function to flip the resulting boolean.
I.e. create a new predicate (\x -> not (oldPred x)), or using function composition: (not . oldPred):
countFilter :: (a -> Bool) -> [a] -> ([a], Int)
countFilter f xs = (filter (not . f) xs, length (filter f xs))
Note that both filter and length can deal with empty lists, so you don't need to write a case yourself.
Alternatively, you can use the partition function to create the two lists, so that you don't filter the list twice:
import Data.List
countFilter :: (a -> Bool) -> [a] -> ([a], Int)
countFilter f xs = let (ys, zs) = partition (not . f) xs
in (ys, length zs)
It's probably possible to create an even more efficient version that doesn't use length, but I leave that as an exercise :-)