Erlang swap two element in list - list

How can I quickly swap two elements in Erlang list?
For example I have list: [1,2,3,4], how can I quickly get [1,3,2,4]?

You did not say in your question how you want to specify which two element you want to swap.
If you just want to swap the elements at position 2 and 3 in a list (like in your example):
swap23([A,B,C|Rest]) ->
[A,C,B|Rest].

Well if you wish to swap any index with another you can do the following
swap(List,S1,S2) -> {List2,[F|List3]} = lists:split(S1-1,List),
LT = List2++[lists:nth(S2,List)|List3],
{List4,[_|List5]} = lists:split(S2-1,LT),
List4++[F|List5].

With this code you only traverse the list once.
swap(A, B, List) ->
{P1, P2} = {min(A,B), max(A,B)},
{L1, [Elem1 | T1]} = lists:split(P1-1, List),
{L2, [Elem2 | L3]} = lists:split(P2-P1-1, T1),
lists:append([L1, [Elem2], L2, [Elem1], L3]).
Usage example:
1> swap(6,2,[1,2,3,4,5,6,7,8]).
[1,6,3,4,5,2,7,8]

Related

How do I bag elements of tuples in Prolog lists

Say I have a list:
Os = [(4,P1),(9,P2),(4,P3),(1,P4),(9,P5)].
I want to put every second element of the tuple in a bag that has the same first element like this:
SortedOs = [(4,[P1,P3]),(9,[P2,P5]),(1,P4)].
Currently I'm using bagof/3:
findall(
(O,Bag),
bagof(P,member((O,P),Os),Bag),
SortedOs
).
But instead it gives me the sorted list like this:
SortedOs = [(1,P4),(4,[P1,P3]),(9,[P2,P5])]
Which means bagof/3 looks up the first element in ascending order. Is there any way I can change this to get the list I want? Many thanks.
If you are using SWI-Prolog and you can change the format of the data from tuples to Pairs, (Key-Value) then you can use group_pairs_by_key/2.
Note that for group_pairs_by_key/2 to work correctly the input list must be sorted.
Code
example(Pairs0,Result) :-
sort(Pairs0,Pairs1),
group_pairs_by_key(Pairs1,Result).
Example usage
?- Pairs = [4-P1,9-P2,4-P3,1-P4,9-P5],example(Pairs,Result).
Pairs = [4-P1, 9-P2, 4-P3, 1-P4, 9-P5],
Result = [1-[P4], 4-[P1, P3], 9-[P2, P5]].
SWI-Prolog has a library of predicates for working with ordered sets (sorted list). ordsets.pl -- Ordered set manipulation
Here is a variation that checks if the input is an ordered set and skips the sorting if it is an ordered set.
example(List,Result) :-
(
is_ordset(List)
->
Order_set = List
;
list_to_ord_set(List,Order_set)
),
group_pairs_by_key(Order_set,Result).
Example usage
?- List = [1-P4, 4-P1, 4-P3, 9-P2, 9-P5],example(List,Result).
List = [1-P4, 4-P1, 4-P3, 9-P2, 9-P5],
Result = [1-[P4], 4-[P1, P3], 9-[P2, P5]].
?- List = [4-P1,9-P2,4-P3,1-P4,9-P5],example(List,Result).
List = [4-P1, 9-P2, 4-P3, 1-P4, 9-P5],
Result = [1-[P4], 4-[P1, P3], 9-[P2, P5]].
Note: Ordered Sets remove duplicates so using list_to_ord_set/2 instead of sort/2 will remove duplicates.
?- List = [4-P1,4-P1,9-P2,4-P3,1-P4,9-P5],example(List,Result).
List = [4-P1, 4-P1, 9-P2, 4-P3, 1-P4, 9-P5],
Result = [1-[P4], 4-[P1, P3], 9-[P2, P5]].
group_pairs_by_key/2 (source code)

Lexicographically sorting a list of neasted lists

Consider the following nested list:
[["AXY"],["ABC","XYZ"],["EFG","ACF"]]
I would like to sort the list lexicographically by the first element of each inner list. The output should be:
[["ABC","XYZ"],["AXY"],["EFG","ACF"]]
If the task have been to sort only one list, I would use one of the methods in the following thread (link). But how can I sort a nested list?
Assuming you have a generic sort function taking a cmp function (like the one shown at the bottom of this answer), you just need to write one taking two string lists:
fun cmpnest ((x::xs):string list, (y::ys):string list) = if x > y then GREATER else LESS
| cmpnest ((x::xs):string list, nil) = GREATER
| cmpnest (nil, _) = LESS
After you have that, you can use it in your generic sort function:
- sort cmpnest [["AXY"], ["ABC", "XYZ"], ["EFG", "ACF"]];
> val it = [["ABC", "XYZ"], ["AXY"], ["EFG", "ACF"]] : string list list
As an addition to L3viathan's answer, you can also use String.compare:
fun cmpnest (x::_, y::_) = String.compare (x, y)
| cmpnest (_::_, []) = GREATER
| cmpnest ([], _) = LESS

Take out first elements from nested lists in Prolog

Problem: I need to transform this list: [[1,2],[3,4],[5,6]] to [1,3,5], by taking only first items from each sub-list in first list and creating new list with all of them. Language is SWI-Prolog.
My solution: To do this, I wrote this code:
getFirstItems([], Result).
getFirstItems([H|T], Result) :-
[H2|T2] = H,
append(Result,H2,Result2),
getFirstItems(T, Result2).
Issue: But this fails to infinite recursion when tail always equals to [[5,6]]
Question: how to solve this issue and solve this problem correctly?
You are complicating things too much. You need to reason with a declarative mindset, and thus implement what the relationships between the list of lists and the list of first elements are.
Here is a solution:
first_items([], []).
first_items([[H|_]|T], [H|T2]) :-
first_items(T, T2).
Indeed, the only two things we need to state to describe that relationship are:
If the list of lists is empty, then so is the list of first elements.
a first element H is in the list of first elements, followed by the first elements (T2) of the rest of the list of lists (T).
Example queries:
?- first_items([[1,2],[3,4],[5,6]], Z).
Z = [1, 3, 5].
?- first_items(L, [1,3,4]).
L = [[1|_22058], [3|_22070], [4|_22082]].
?- first_items(L, Z).
L = Z, Z = [] ;
L = [[_22048|_22050]],
Z = [_22048] ;
L = [[_22048|_22050], [_22066|_22068]],
Z = [_22048, _22066]
…

Merge two List ["String",Float] into new list ["String",Float,Float]

We need to merge both lists into one who takes de number of frequency who a word appears in lists.
If we have:
`List 1 [("Hi", 0.45),("Steve", 0.0.5),("Bye",0.9)]...`
`List 2 [("Hello", 0.56), ("Steve", 0.6), ("Bye", 0.6)]..`
we want to get: [("Hi",0.45,0), ("Steve", 0.0.5, 0.6)...
mergeLists :: [(a,Float)] -> [(a,Float)] -> [(a,Float,Float)]
mergeLists v y = map (\x -> ( fst x, if not (elem (fst x) v) then 0
else 5 ,
if not (elem (fst x) v) then 5
else 0))y
Now we are doing by the following code, but we have a lot of problems to continue.
I'm trying to go forward the first list, if list2 doesn't contains the element write 0, otherwise write the frequency value of both lists into the new one.
This is easy when working with sorted lists. You need to augment the usual union function definition in that case, adapting it to your specific data type, like
mergeOrderedLists a b = go a b
where go a#((x,n):t) b#((y,m): ..... ) = case compare x y of
LT -> (x,n,0) : go t b
EQ -> ....... : go t r
GT -> ....... : go a r
go [] b = ......
......
you will have to complete the missing cases here (and for the empty lists too).
You will have to sort each of the argument lists to be able to use this function, to define what you describe.
Is it important to preserve the order of the lists? If not, you can do this with Data.Map. This gives you a map where the key is each word and the value is a [Float]. As a bonus you can combine as many lists this way as you want.
import Control.Arrow (second)
M.fromListWith (++) $ map (second (:[])) $ list1 ++ list2

Swap first and last element haskell

Im trying to swap the first and last element of a list in haskell. I've tried pattern matchnig, expressions, functions, etc. This is my last attempt:
cambio xs = [ cabeza++([x]++cola)|x<-xs, cabeza <- init x, cola <- last x, drop 1 x, drop 0 ([init x])]
My compiler throws the next error:
Couldn't match expected type `Bool' with actual type `[a0]'
In the return type of a call of `drop'
In the expression: drop 1 x
In a stmt of a list comprehension: drop 1 x
Can anyone help me? I've tried to do this for 2 days
Here are a few hints:
You can't solve this with list comprehension.
Identify the base (trivial) cases - empty list and list of one element. Write equations that cover those cases.
In all other cases the length of the input list will be >= 2. The list you want is
[z] ++ xs ++ [a]
where z is the last element, a the first element of the input list and xs the middle part of the input.
Now tell me (or yourself), how long will xs be, if the length of the input string was k?
Write the equation that covers the case of lists with more than 1 elements. You can use functions like head, last, length, drop or take.
I think that lists aren't the best data structure for doing this, but here it goes:
swap list = last list : (init . tail $ list) ++ [head list]
This is going to require traversing the list and will be slow on long lists. This is the nature of linked lists.
Updated with base cases from question asker:
swap [] = []
swap [a] = [a]
swap list = last list : (init . tail $ list) ++ [head list]
This is a fairly straightforward thing to do, especially with the standard list functions:
swapfl [] = []
swapfl [x] = [x]
swapfl (x:xs) = (last xs : init xs) ++ [x]
Or without them (although this is less readable and usually not done, and not recommended):
swapfl' [] = []
swapfl' [x] = [x]
swapfl' (x:xs) = let (f, g) = sw x xs in f:g
where sw k [y] = (y, [k])
sw k (y:ys) = let (n, m) = sw k ys in (n, y:m)
Or one of many other ways.
I hope that helps ... I know I didn't do much explaining, but frankly, it's hard to tell exactly what you were having trouble with as far as this function is concerned, seeing as you also seem to completely misunderstand list comprehensions. I think it might be most beneficial if I explain those instead?
And why this cant be solved with a list comprehension? I tough they were like functions but with a different form
Not really. List comprehensions are useful for easily defining lists, and they're very closely related to set-builder notation in mathematics. That would not be useful for this particular application, because, while they're very good at modifying the elements of a list, comprehensions are not very good at reordering lists.
In a comprehension, you have three parts: the definition of an element in the list, one or more input lists, and zero or more predicates:
[ definition | x <- input1, y <- input2, predicate1, predicate2 ]
The definition describes a single element of the list we're making, in terms of the variables the arrows in the inputs are pointing at (x and y in this case). Each input has a list on the right of the arrow, and a variable on the left. Each element in the list we're making is built by extracting each combination of elements from the input lists into those variables, and evaluating the definition part using those values. For example:
[ x + y | x <- [1, 3], y <- [2, 4] ]
This generates:
[1 + 2, 1 + 4, 3 + 2, 3 + 4] == [3, 5, 5, 7]
Also, you can include predicates, which are like filters. Each predicate is a boolean expression defined in terms of the input elements, and each is evaluated whenever a new list element is. If any of the predicates come out to be false, those elements aren't put in the list we're making.
Let's look at your code:
cambio xs = [ cabeza++([x]++cola) | x<-xs, cabeza <- init x, cola <- last x,
drop 1 x, drop 0 ([init x])]
The inputs for this comprehension are x <- xs, cabeza <- init x, and cola <- last x. The first one means that every element in xs is going to be used to define elements for the new list, and each element is going to be named x. The other two don't make any sense, because init and last are type [a] -> a, but are on the right side of the arrow and so must be lists, and x must be an element of a list because it's on the left side of its arrow, so in order for this to even compile, xs would have to be type [[[a]]], which I'm sure is not what you want.
The predicates you used are drop 1 x and drop 0 [init x]. I kind of understand what you were trying to do with the first one, dropping the first element of the list, but that wouldn't work because x is just an element of the list, not the list itself. In the second one, drop 0 means "remove zero elements from the beginning of the following list", which would do absolutely nothing. In either case, putting something like that in a predicate wouldn't work because the predicate needs to be a boolean value, which is why you got the compiler error. Here's an example:
pos xs = [ x | x <- xs, x >= 0 ]
This function takes a list of numbers, removes all the negative numbers, and returns the result. The predicate is the x >= 0, which is a boolean expression. If the expression evaluates to false, the element being evaluated is filtered out of the resulting list.
The element definition you used is cabeza ++ [x] ++ cola. This means "Each element in the resulting list is itself a list, made up of all elements in the list cabeza, followed by a single element that contains x, followed by all elements in the list cola", which seems like the opposite of what you were going for. Remember that the part before the pipe character defines a single element, not the list itself. Also, note that putting square brackets around a variable creates a new list that contains that variable, and only that variable. If you say y = [x], this means that y contains a single element x, and doesn't say anything about whether x is a list or not.
I hope that helps clear some things up.