How to change of list of tuples, like
[(5,6),(7,8),(9,10)]
into a normal list, like
[5,6,7,8,9,10]
via list comprehensions and without concat?
I have tried this:
[ [y, z] | xs <- [(1,2),(3,4)], y <- fst(xs), z <- snd(xs) ]
To flatten any list with a list comprehension, the form is always the same. Take the multiple elements from the source one-at-a-time.
List comprehensions, like functions let you specify and exact pattern of the source, tuple or list.
Your function is not in the form of multiples, one-at-a-time, so correcting it will never give you what you want. It will, at very least require the use of concat to concatenate the output.
Here is the form of a flattening list comprehension
[ n |(a,b)<-[(1,2),(3,4),(5,6)],n <-[a,b]]
a and b are taken one-at-a-time by n, to flatten.
Related
I'm trying to learn OCaml since I'm new to the language and I stumbled across this problem where I can't seem to find a way to see, in a function where I need to merge 2 kinds of these lists, if there is already an element with a key, and if so how to join the elements that come after. Would appreciate any guidance.
For example if I have:
l1: [(k, [e]); (ka, [])]
l2: [(k, [f; g])]
How can I end up with:
fl: [(k, [e; f; g]); (ka, [])]
Basically, how can I filter the key k from both lists while making their elements combine.
There are functions in the standard OCaml library for dealing with lists of pairs where the first element of each pair is a key. You will find them described here: https://ocaml.org/releases/4.12/api/List.html under Association lists.
I will repeat what #ivg says. This is not how you want to solve your problem if you have more than just a few pairs to work with.
First of all, using lists as mappings is a bad idea. It is much better to use dedicated data structures such as maps and hash tables.
Answering your question directly, you can concatenate two lists using the (#) operator, e.g.,
# [1;2;3] # [4;5;6];;
- : int list = [1; 2; 3; 4; 5; 6]
If you don't want repetitive elements when you merge then, and I feel like I repeat myself, it is bad to use lists for sets, it is better to use dedicated data structures such as sets and hash sets. But if you want to continue, then you can merge two lists without repetitions by checking if an element is already in the list before prepending to it. Easy to implement but hard to run, in a sense that it takes quadratic time to merge two lists this way.
If you still want to stick with the list of pairs, then you will find that the List.assoc function is useful, as it finds a value by key. The overall algorithm would be, given two lists, xs and ys, fold over elements of ys using xs as the initial value acc, and for each (ky,y) in ys if ky is already in acc, find the associated with ky value x and remove (List.remove_assoc) it, then merge x and y and prepend the merged value with the acc list, otherwise (if it is not in acc) just prepend (ky,y) to acc`. Note that this algorithm doesn't preserve order, so if it matters you need something more complex. Also, if your keys are sorted you can make it a little bit more efficient and easier to implement.
I guess you're doing this to practice with list.
What I would do is store the already found keys in an accumulator
let mergePairs yourList =
let rec aux accKeys = function
| [] -> []
| x :: xs -> let k,v = x in if (* k in accKeys *) then aux accKeys xs (*we suppress already
existing keys*)
else (k, v # (* get all the list of the other pairs with key = k in xs*))
:: aux (k::accKeys) xs
in aux [] yourList;;
I've done my research already and I can't find anything similar. I need to split a list of two lists in two separated lists, for example: [ [[1,2],[2],[3]], [[3], [2,3], [5]] ] -> results in [[1,2],[2],[3]] and [[3], [2,3], [5]] .
I tried this but I can't seem to find where I need to change the code:
split([],[],[]).
split([H|T],X,Y):-
X = H,
Y = T.
You can just unpack the list in two parameters:
split([L1, L2], L1, L2).
Here we thus unify the first parameter with [L1, L2] such that the list of length two is unified in that way that L1 unifies with the first item (sublist), and L2 with the second item (sublist).
Im very confused on how to filter out the element (1,1) from this list in the code below.
take 10 [ (i,j) | i <- [1,2],
j <- [1..] ]
yields
[(1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8),(1,9),(1,10)]
My thoughts were to use something like filter but Im not too sure where to implement it.
My go was Filter ((i,j) /=0) "the list"
Thanks
Your attempt
Filter ((i,j) /=0) "the list"
has a few problems, which can be fixed.
First, the function is called filter. Second, its first argument must be a function: so you can use \(i,j) -> ... to take a list as input. Third, you want (i,j) /= (1,1) -- you can't compare a pair (i,j) to a single number 0.
You should now be able to correct your code.
As an alternative to using filter, you can also specify that you don't want (1,1) as an element within your list comprehension by adding a guard expression (i,j) /= (1,1):
take 10 [ (i,j) | i <- [1,2], j <- [1..], (i,j) /= (1,1) ]
This is similar to how you might write a set comprehension (which list comprehensions mimic):
This answer gives a nice example ([x | i <- [0..10], let x = i*i, x > 20]) of the three types of expression you can have in the tail end of a list comprehension:
Generators, eg. i <- [0..10] provide the sources of values.
Guards, eg. x > 20 are arbitrary predicates - for any given values from the generators, the value will only be included in the result if all the predicates hold.
Local declarations, eg. let x = i*i perform the same task as normal let/where statements.
Names for the different expressions taken from the syntax reference, expression qual.
So I'm new to Erlang and still on the learning curve, one question asked was to return all elements in a list followed by an equal element, to which I could to.
For example...
in_pair_lc([a,a,a,2,b,a,r,r,2,2,b,a]) -> [a,a,r,2]
I was then asked to do the same using a list comprehension, and I hit my mental block.
My unsuccessful attempt was this:
in_pair_lc([]) -> [];
in_pair_lc([H|T]) ->
[X || X ,_ [H|T], X=lists:nth(X+1, [H|T]).
Although with no look ahead in list comp it doesn't work.
Thanks for any help in advance.
One way to do this with a list comprehension is to create two lists from the input list:
one containing all elements except the very first element
one containing all elements except the very last element
By zipping these two lists together, we get a list of tuples where each tuple consists of adjacent elements from the input list. We can then use a list comprehension to take only those tuples whose elements match:
in_pair_lc([_|T]=L) ->
[_|T2] = lists:reverse(L),
[H || {H,H} <- lists:zip(lists:reverse(T2),T)].
EDIT: based on the discussion in the comments, with Erlang/OTP version 17.0 or newer, the two list reversals can be replaced with lists:droplast/1:
in_pair_lc([_|T]=L) ->
[H || {H,H} <- lists:zip(lists:droplast(L), T)].
The first example will work on both older and newer versions of Erlang/OTP.
I'm not convinced the problem is really about list comprehensions. The core of the problem is zipping lists and then using a trivial "filter" expression in the list comprehension.
If you want to stick to basic, long existing, erlang list functions (sublist, nthtail) you could go with the following:
X = [a,a,a,2,b,a,r,r,2,2,b,a].
[A || {A,A} <- lists:zip(lists:sublist(X, length(X)-1), lists:nthtail(1, X))].
Is there a way in SWI-Prolog to represent a list of empty lists?
like:
[[],[]],
[[],[],[]],
[[],[],[],[]]
I want something like this
[[]|[]]
[[],[]], [[],[],[]] and [[],[],[],[]] are all different things - number of elements in each list is different.
Maybe you what a predicate that will be true if the argument is a list with the length of at least 1 and those elements are empty lists:
lel([[]]).
lel([[] | T]) :-
lel(T).
Btw, [[]|[]] is the same as [[]].