Erlang creating list by splitting a list of tuples - list

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).

Related

Create List by multiplying object with [1..n]

I am still not into Haskell and need a hint for the following function.
I want to create a list by adding each multiplication of a pair:
all :: Int -> (Int,Int) -> [(Int, Int)]
all n, pair = ...
E.g. n = 3, pair (1,2) => [(1,2), (2,4), (3,6)]
which expands to [(1*(1,2)), ((2*(1,2)), (3*(1,2))]
I know its something with x <- [1..n] and x*pair but I don't know which built-in function is right to put it together!
You need to do the multiplication separately on the elements in the tuples, and then recreate a tuple. You can use fst and snd to get the elements.
all n pair = [(x*(fst pair), x*(snd pair)) | x <- [1..n]]
Pattern matching is another common way to access tuple elements.
all n (a, b) = [(x*a, x*b) | x <- [1..n]]

Creating List of Lists in Erlang

For example I have a list [1,3,5] and another list [2,4,6], how do I append these two lists in such way it will form into a List of Lists like this: [[1,3,5],[2,4,6]]?
How do I manipulate the list if I add another list at the end [7,8,9] to look like [[1,3,5],[2,4,6],[7,8,9]]?
L1 = [1,3,5],
L2 = [2,4,6],
[L1,L2].
You just need create a list containing both lists.
A = [1,3,5],
B = [2,4,6],
[A, B].
-module(lol).
-export([new/0, append/2, head/1, tail/1]).
new() -> [].
append(H, []) when is_list(H) -> [H];
append(H, T) when is_list(H) -> [H | T].
head([H | _]) when is_list(H) -> H.
tail([_ | T]) -> T.
In the shell you could then:
> Herp = lol:append([1,3,4], lol:new()).
[[1,2,3]]
> Derp = lol:append([4,5,6], Herp).
[[4,5,6],[1,2,3]]
> lol:head(Derp).
[4,5,6]
I leave the rest as exercise for the user.
1> [1,2,3 | [1,2,3]].
[1,2,3,1,2,3]
2> lists:append([1,2,3], [1,2,3]).
[1,2,3,1,2,3]

Remove duplicate elements from a list in Erlang

How can I remove the duplicate from a list in Erlang?
Suppose I have a list like:
[1,1,2,3,4,5,5,6]
How can I get:
[1,2,3,4,5,6]
You could use sets, for example:
my_nonDuplicate_list1() ->
List = [1,1,2,3,4,5,5,6],
Set = sets:from_list(List),
sets:to_list(Set).
This returns [1,2,3,4,5], no more duplicates, but most likely not sorted.
Another possibility without the usage of sets would be:
my_nonDuplicate_list2() ->
List = [1,1,2,3,4,5,5,6],
lists:usort(List).
In this case it returns [1,2,3,4,5], no more duplicates and sorted.
And for those looking to preserve the order of the list:
remove_dups([]) -> [];
remove_dups([H|T]) -> [H | [X || X <- remove_dups(T), X /= H]].
A possible solution that will Preserve the order of the elements to help you learn how to manipulate lists, would involve two functions:
delete_all(Item, [Item | Rest_of_list]) ->
delete_all(Item, Rest_of_list);
delete_all(Item, [Another_item| Rest_of_list]) ->
[Another_item | delete_all(Item, Rest_of_list)];
delete_all(_, []) -> [].
remove_duplicates(List)-> removing(List,[]).
removing([],This) -> lists:reverse(This);
removing([A|Tail],Acc) ->
removing(delete_all(A,Tail),[A|Acc]).
To test,
Eshell V5.9 (abort with ^G)
1> mymod:remove_duplicates([1,2,3,1,2,4,1,2,1]).
[1,2,3,4]
2>
I would do something like this at first to preserve order, though it is not recommended. Remember that AddedStuff ++ Accumulator is OK but Accumulator ++ AddedStuff is really bad.
rm_dup(List) ->
lists:foldl(
fun(Elem, Acc) ->
case lists:member(Elem, Acc) of
true ->
Acc;
false ->
Acc ++ [Elem]
end
end, [], List
).
This solution is much more efficient if you want to preserve order:
rm_dup(List) ->
lists:reverse(lists:foldl(
fun(Elem, Acc) ->
case lists:member(Elem, Acc) of
true ->
Acc;
false ->
[Elem] ++ Acc
end
end, [], List
)).
for my opinion, the best option is to use lists:usort()
But in case you don't want to use BIF's, and you want the list to be sorted, I suggest a version of quick sort, in this implementation you will get the list sorted without duplicate values.
unique_sort([]) -> [];
unique_sort([Pivot|T]) ->
unique_sort ([X || X <- T, X < Pivot ) ]++
[Pivot] ++
unique_sort ([X || X <- T, X > Pivot ]).
Module sets has two functions that can be composed and do the job in an efficient way: sets:from_list/1 returns a set with all the elements of a list (with no duplicated elements from definition) and sets:to_list/1 returns a list with the elements of a set. Here is an example of use:
4> sets:to_list(sets:from_list([1,1,2,3,4,5,5,6])).
[3,6,2,5,1,4]
We could define the function as
nub(L) -> sets:to_list(sets:from_list(L)).

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.