Erlang list generation - list

I have 2 list:
["asd", "dsa"].
[[123, "asd"], [4534, "fgh"]].
How can i generate next list: I ned list that tail of each nested list =:= other element of 1 list.
In this example:
["asd", "dsa"].
[[123, "asd"], [4534, "fgh"]].
"asd" =:= "asd" ->
Output list:
[123, "asd"]
I try:
Here S = [[123, "asd"], [4534, "fgh"]].
D = ["asd", "dsa"].
List = lists:filter(fun(X) ->
lists:last(X) =:= D end, S),
But D in this example list, and i need element of list.
How can do it?

Maybe something like:
1> [X || X<-[[1,2,4],[7,8,3],[2,5,4],[9,1,6]], Y<-[4,3], lists:last(X)=:=Y].
[[1,2,4],[7,8,3],[2,5,4]]
Or, using your sample data:
2> [X || X<-[[123,"asd"], [4534,"fgh"]], Y<-["asd","dsa"], lists:last(X)=:=Y].
[[123,"asd"]]

A slightly more direct way of writing it would be:
lists:filter(fun (X) -> lists:member(lists:last(X), D) end, S).
or with list comprehensions:
[ X || X <- S, lists:member(lists:last(X), D) ].
They are a little faster as they will not attempt to match against more elements in D if the element is found. Expanding D in the comprehension will do this.

Related

How to remove elements of a list?

I have implemented a function which deleting elements of a list one by one:
remove(_,[])->
[];
remove(Elem, L)->
Rest = lists:delete(Elem,L),
remove(Elem,Rest).
But it hangs when I tried with this example:
L = [1,2,3,4].
remove(hd(L), [L]).
What is wrong with it? Or is there a better way to delete elements in the list one by one starting from the first element of a list.
It makes an infinite loop. First, you call
remove(1, [1,2,3,4]) ->
[2,3,4] = lists:delete(1, [1,2,3,4]),
remove(1, [2,3,4]).
So you call
remove(1, [2,3,4]) ->
[2,3,4] = lists:delete(1, [2,3,4]),
remove(1, [2,3,4]).
And then you call it again with the same input and again and again.
One way to fix it is to check if lists:delete/2 returns same result
remove(Elem, L)->
case lists:delete(Elem,L) of
L -> L;
Rest -> remove(Elem,Rest)
end.
(Function clause remove(_,[]) is not necessary even it doesn't do any harm.)
But there is a more strightforward approach:
remove(_, []) -> [];
remove(H, [H|T]) ->
remove(H, T);
remove(X, [H|T]) ->
[H | remove(X, T)].
Which could be written using list comprehensions:
remove(X, L) ->
[Y || Y <- L, Y =/= X].
The resulting code will be basically the same.
You can also use the lists module, it has a lot of useful functions defined.
Take this for example, for you case:
1> A = [1,2,3,4,5,6,7,8,9,10].
[1,2,3,4,5,6,7,8,9,10]
2> B = [2,3,4].
[2,3,4]
3> lists:filter(fun (Elem) -> not lists:member(Elem, B) end, A ).
[1,5,6,7,8,9,10]
simple answer is
A = [1,2,3,3,4]
B = [3,4]
A -- B = C
[1,2,3,3,4] -- [3,4] = [1,2,3].

function that uses list comprehensions to generate a list of lists in Haskell

I want to write a function that uses list comprehensions to generate a list of lists that works like this:
makeList 3 == [[1],[1,2],[1,2,3]]
makeList 5 == [[1],[1,2],[1,2,3],[1,2,3,4],[1,2,3,4,5]]
makeList (-2) == []
I end up with this solution, but It not gives me what it needs from the question obviously:
let makelist x = [x | x <- x, y <- [1..x]]
So if I enter this
Prelude> makelist [3]
the output will shows like this:
[3,3,3]
I wanted to be a list in list first then I want it to be increased. Thank you for help!
Let's try generating an inner list first, for some limit m:
> let inner m = [1..m]
> inner 5
[1,2,3,4,5]
Now, observe that your outer list, for some limit n, is [inner 1, inner 2, inner 3, ..., inner n], or, in list comprehension form:
> let outer n = [inner m | m <- [1..n]]
> outer 3
[[1], [1,2], [1,2,3]]
so we can combine the two into the single list comprehension expression:
> let makeList n = [[1..m] | m <- [1..n]]
> makeList 4
[[1],[1,2],[1,2,3],[1,2,3,4]]
I propose you this:
make_list n = [ [1..m] | m <- [1..n] ]
However there's something strange in your first attempt:
make_list x = [x | x <- x, y <- [1..x]]
there you put x for every purpose. It just feels wrong.
A recursive version based in list generation as well,
makeList' :: Int -> [[Int]]
makeList' n
| n < 1 = []
| otherwise = [1..n] : makeList' (n-1)
makeList :: Int -> [[Int]]
makeList n = reverse $ makeList' n
makeList' returns the desired outcome in reverse order.

Erlang creating list by splitting a list of tuples

I have a list of tuples and I want to create the a list of elements from a specific position in the tuple.
My tuple is {A, B} and I have several of these in a list and i want to create the list of all the B elements.
Cheers!
You can use lists:map.
1> A = [{1,2},{3,4},{5,6}].
[{1,2},{3,4},{5,6}]
2> B = lists:map(fun ({_, V}) -> V end, A).
[2,4,6]
The function passed to the map will select the element required from the tuple and the result will be a list of all the elements in that particular position in the given list of tuples. The above code assumes that all tuples have same number of elements.
Yet another way is to just use a simple list comprehension:
[B || {_, B} <- L].
> L = [{a1,b1}, {a2,b2}, {a3,b3}].
[{a1,b1},{a2,b2},{a3,b3}]
> lists:foldr(fun({_, B}, Acc) -> [B | Acc] end, [], L).
[b1,b2,b3]
This is a quick sample, not tested, but it should work.
split_tuples([{A | B} | T], Acc) ->
NewAcc = [B | Acc],
split_tuples(T, NewAcc);
split_tuples([], Acc) ->
lists:reverse(Acc).
erlang's element/2 function does just that: return the nth element from a tuple.
Put that in a map or fold function, with position as a parameter, and you're done.
edit: some untested code example:
get_them_all(ListOfTuples,Index) ->
lists:map(fun(Tuple) -> element(Index,Tuple) end,ListOfTuples).

How can I build a list from another list, creating multiple elements for each element in the original list?

I want to do something like
[(x, y, x+y) | (x,y) <- original]
But of course, this will return something like:
[(0, 0, 0), (0, 1, 1), (1, 1, 2)]
What I want is something like:
[0, 0, 0, 0, 1, 1, 1, 1, 2]
I am quite new to Haskell, and unfamiliar with its idioms. How can I accomplish this in Haskell?
First, a diatribe on types. You are drawing the pair (x,y) from a list named original. Original must be a list of pairs, original :: [(a,b)], such as [(1,6), (4,9)]. You then construct a tuple for each element, hence your result of a list of tuples. I am going by the guess that you never wanted any tuples but actually want some number of elements of the list to be combined by your function and concatenate the results into a new list.
You might looking for the concatMap function:
> :t concatMap
concatMap :: (a -> [b]) -> [a] -> [b]
> concatMap (\x -> [x,x+1,x+7]) [1,2,3]
[1,2,8,2,3,9,3,4,10]
If you actually want to consume two (or more) elements at once then there are a few missing details, such as what to do if you have an odd number of elements and weather or not elements repeat (so you see [1,2,3] as two inputs 1,2 and 2,3).
If elements repeat then this is just a concatMap and a zip:
> let ls = [1,2,3] in concatMap (\(x,y) -> [x,y,x+y]) (zip ls (drop 1 ls))
[1,2,3,2,3,5]
But if you want to see them as [1,2] and [3] then you're best off writing your own function:
func [] = []
func [x] = [[x]] -- What do you want with the odd remaining element?
func (x:y:rest) = [x,y,x+y] : func rest
> concat (func [1,2,3])
[1,2,3,3]
Looks like you're just making a non-deterministic choice -- just what list comprehensions were made for!
[v | (x,y) <- original, v <- [x, y, x+y]]
You can for example create a list of lists and then use concat to flatten it.
concat [[x, y, x+y] | (x, y) <- original]

erlang list filter question

I have list - Sep1:
[
....
["Message-ID", "AAAAAAAAAAAAAAAAAAA"],
["To", "BBBBBBBBBBBBBBBBB"]
...
]
I try get element where first item = Message_ID for example:
lists:filter(fun(Y) -> (lists:nth(1,lists:nth(1,Y)) =:= "Message-ID") end, Sep1).
But i get error:
exception error: no function clause matching lists:nth(1,[])
in function utils:'-parse_to/1-fun-1-'/1
in call from lists:'-filter/2-lc$^0/1-0-'/2
But if i:
io:format(lists:nth(1,lists:nth(1,Sep1))).
> Message-ID
What's wrong?
Thank you.
It's better to change representation to [{Key, Value}, ...] so you can use lists:key* functions, proplists module, or convert it to dict with dict:from_list/1.
But if you still want to use lists:filter/2 you can filter list of lists by first element as following:
lists:filter(fun ([K | _]) -> K =:= "Message-ID" end, ListOfLists).
If you want to extract tails of lists which first element match with "Message-ID" you can use list comprehensions:
[Tail || ["Message-ID" | Tail] <- ListOfLists].
Why do you use two nested lists:nth calls?
lists:filter(fun(Y) -> lists:nth(1, Y) =:= "Message-ID" end, Sep1) works for me and returns a list containing the elements you want (lists where the first element is "Message-ID"). Just pattern match on that list to get the element you want, e.g. if you want only one such element you can do:
case lists:filter(fun(Y) -> lists:nth(1, Y) =:= "Message-ID" end, Sep1) of
[Result] -> % do something with it;
[] -> % no such element found
end
What you probably want is this:
[B || [A,B|_] <- L, A =:= "Message-ID"].
This does not assume any length of the nested lists:
It will return a list of the second elements of all inner lists whose first element is "Message-ID"
If you are sure there is only one "Message-ID" and want to throw an error otherwise:
[X] = [B || [A,B|_] <- L, A =:= "Message-ID"].
If you only want the first one (still throwing error when there is none):
[X|_] = [B || [A,B|_] <- L, A =:= "Message-ID"].
To understand what this code does I recommend reading official Erlang documentation about list comprehensions and the Learn You Some Erlang-chapter about the same topic: List Comprehensions.
Assuming that your list contains only elements each of them with 2 elements, you could use lists comprehension doing something like this:
1> L = [["Message-ID","AAAAAAAA"],["To","BBBBBBBBBBB"]].
[["Message-ID","AAAAAAAA"],["To","BBBBBBBBBBB"]]
2> [[A,B]||[A,B] <- L, A =:= "Message-ID"].
[["Message-ID","AAAAAAAA"]]
Hope this helps.
You could create your own filter (which doesn't care about the number of the elements):
filter(List) -> filter(List,[]).
filter([],Acc) -> lists:reverse(Acc);
filter([[]|Tail],Acc) -> filter(Tail,Acc);
filter([[H|T]|Tail],Acc) ->
case H =:= "Message-ID" of
true -> filter(Tail,[[H|T]|Acc]);
_ -> filter(Tail,Acc)
end.