Generate variations with repetitions Erlang - erlang

I've found a way to generate the combinations of a list, but here order doesn't matter, but I need to generate variations where order matters.
Combination:
comb_rep(0,_) ->
[[]];
comb_rep(_,[]) ->
[];
comb_rep(N,[H|T]=S) ->
[[H|L] || L <- comb_rep(N-1,S)]++comb_rep(N,T).
Output of this:
comb_rep(2,[1,2,3]).
[[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]]
Desired output:
comb_rep(2,[1,2,3]).
[[1,1],[1,2],[1,3],[2,2],[2,3],[3,1],[3,2],[3,3]]

Following what’s explained in the comments, this will be my initial approach:
cr(0, _) ->
[];
cr(1, L) ->
[ [H] || H <- L ];
cr(N, L) ->
[ [H | T] || H <- L, T <- cr(N - 1, L -- [H]) ].
Permutations of length 0 is an edge case. I would even consider the removal of that clause so that the function fails if invoked as such.
Permutations of length 1 means just means each element in its own list.
Then, for the recursive case, if you already have the permutations of the list without the current element (cr(N - 1, L -- [H])) you can just add that element to the head of each list and you just need to do that for each element in the original list (H <- L).
Hope this helps.

Related

Why doesn't this sequence generation work?

I'm facing with the generation of all the k-combinations (without repetition) of a list of elements. Beside the possible optimization in the code I wrote this function which I was almost sure it should work:
// comb :: int -> 'a list -> seq<'a list>
// Generates a sequence of all combinations (no repetition)
let comb k xs =
// subs :: 'a list -> seq<'a list>
// Splits a list in its subsequent non-empty tails
let rec subs xs =
seq {
match xs with
| _::ys -> yield xs
yield! subs ys
| _ -> yield! []
}
let rec comb' k xs rs =
seq {
for zs in subs xs do
match k, zs with
| 0, _ -> yield rs // Solution reached
| _ when k > List.length zs -> yield! [] // Safety (and optimizing) guard
| _, y::ys -> yield! comb' (k - 1) ys (y::rs) // Let's go deeper
| _ -> yield! [] // Not a solution
}
comb' k xs []
The idea behind this algorithm is to "traverse" the tree of all possible combinations and select only the ones with k elements; the subs function is used to generate the sub-sets of elements to generate the sub-trees in the same level; that is, calling:
Seq.toList <| subs [1..3];;
produces:
[[1;2;3];[2;3];[3]]
Maybe this part is a bit confusing, but it shouldn't be part of the problem and I don't think the issue is there.
The algorithm doesn't keep the order of the elements, but it's not necessary for my purpose.
Making a simple test case:
Seq.toList <| comb 2 [1..3];;
I was expecting the three solutions:
[[2;1];[3;1];[3;2]]
but actually it returns only:
[[2;1]]
I debug a little with VS Code, but I didn't really understand how the execution flows.
Does anybody see where the problem is?
Update
I realized that I badly exposed the concept behind the algorithm.
I visualized the solution to the problem like a search tree; at every level the root of a subtree contains the solution obtained by the concatenation of the head of all the remaining tails (subs results) and the list of the parent node.
Comparing the size of the tails and the current value of k I am able to understand which branches can actually contain solutions.
Your code is nearly right. The only issue is that when xs is empty in comb', then subs will be empty (since there are no non-empty tails) even when k is 0, but you should be yielding rs in that case, too.
This can easily be fixed by testing if k is 0 outside of the for loop and yielding rs there, and then putting the for loop into the else branch (where now you only need to match on zs):
let rec comb' k xs rs =
seq {
if k = 0 then yield rs
elif k <= List.length xs then
for zs in subs xs do
match zs with
| y::ys -> yield! comb' (k - 1) ys (y::rs) // Let's go deeper
| [] -> yield! [] // Not a solution
}
Well, your solution is very confusing, and it's no wonder that it produces incorrect results. Very hard to understand, very hard to follow.
Problem 1: subs doesn't actually produce all possible subsets. Look: in your very own experiment you're saying that subs [1..3] produces [[1;2;3]; [2;3]; [3]]. But this is incorrect: [1;3] is also a possible subset, but it's missing!
If you look carefully at what subs is actually doing, you'll see that at every iteration it emits the current value of xs, and then calls itself passing the tail of xs as argument. This, very predictably, leads to a sequence of all tails of the original list.
One obvious way to produce all possible subsets is by, at every iteration level, to produce a sequence of lists with one element removed:
let rec subs xs =
if List.isEmpty xs then Seq.empty
else
seq {
yield xs
for i in 0..(List.length xs - 1) do
let xsWithoutI = (List.take i xs) # (List.skip (i+1) xs)
yield! subs xsWithoutI
}
But of course, this will generate repetitions:
> subs [1..3] |> Seq.toList
val it : int list list =
[[1; 2; 3]; [2; 3]; [3]; [2]; [1; 3]; [3]; [1]; [1; 2]; [2]; [1]]
I will leave it as an exercise to come up with a way to exclude repetitions.
Problem 2 the function comb' doesn't make sense at all. At every iteration, zs is one of the possible subsequences (from subs), which you then match with y::ys, thus making y the first element of that subsequence, and ys - its tail. Then you prepend the first element of the subsequence to the result, and recur. This means that you're gradually building up the result out of first elements of every subsequence, but in reverse order (because you're prepending). So naturally, the result is [2;1]: 2 is the first element of the second subsequence, and 1 is the first element of the first subsequence.
The approach doesn't make sense to me at all. I don't see what the thought process could have been that lead to this implementation.
If you have a sequence of all posisble subsequences (from subs), and you want only those that are k elements long, why not just filter by that?
let comb' k xs = subs xs |> Seq.filter (fun s -> List.length s = k)
> comb' 2 [1..3]
val it : seq<int list> = seq [[2; 3]; [1; 3]; [1; 2]]

Non decreasing list of lists

I've been trying to implement a function that takes a list of integers and then return a list of lists of integers which are non-decreasing.
i.e
let ls = [ 1;2;3;5;6;3;2;5;6;2]
I should get [[1;2;3;5;6];[3];[2;5;6];[2]]
How should i approach this ? i'm a total noob at functional programming.
I can think of the steps needed:
1. Start a new sublist, compare each element with the one next to it. if it is greater then add to list. if not, start a new list and so on.
From what I've learned so far from the book Functional Programming with f# ( which i just started a few days ago), I could possibly use pattern matching and a recursive function maybe to go through the list comparing two elements
something like this :
let rec nonDecreasing list =
match list with
| (x,y) :: xs when x <= y ->
how would I go about to create the sublists using pattern matching ?
or have i approached the question wrongly?
Since there's already a solution using fold, here's another answer using foldBack, so you don't have to reverse it. Now you can backout a pure recursive solution.
let splitByInc x lls = // x is an item from the list, lls is a list of lists
match lls with
| y::xs -> // split the list of lists into head and tail
match y with
| h::_ when x <= h -> (x::y)::xs // take the head, and compare it with x, then cons it together with the rest
| _ -> [x]::lls // in the other case cons the single item with the rest of the list of lists
| _ -> [[x]] // nothing else to do, return the whole thing
let ls = [ 1;2;3;5;6;3;2;5;6;3]
List.foldBack splitByInc ls [] //foldBack needs a folder function, a list and a starting state
Edit:
Here's a really simplified example, you could write a recursive sum and compare it with the fold version:
let sumList x y =
x + y
List.foldBack sumList ls 0 //36
To better understand what splitByInc does, try it out with these examples:
splitByInc 4 [[5;6;7]] // matches (x::y)::xs
splitByInc 4 [] // matches [[x]]
splitByInc 4 [[1;2;3]] // matches [x]::lls
That's basically the same answer as the one given by #s952163 but maybe more readable by removing the nested match and also more general by adding a comparison function to do the "packing".
let packWhile predicate list =
let folder item = function
| [] -> [[ item ]]
| (subHead :: _ as subList) :: accTail
when predicate item subHead -> (item :: subList) :: accTail
| accList -> [ item ] :: accList
List.foldBack folder list []
// usage (you can replace (<=) by (fun x y -> x <= y) if it's clearer for you)
packWhile (<=) [1;2;3;5;6;3;2;5;6;3]
// you can also define a function to bake-in the comparison
let packIncreasing list = packWhile (<=) list
packIncreasing [1;2;3;5;6;3;2;5;6;3]
I'd use a fold, where your 'State is a tuple containing the previous value, the list of lists, and the current non-decreasing list you're working on.
let ls = [ 1;2;3;5;6;3;2;5;6;3]
let _, listOfLists, currList =
((Int32.MinValue, [], []), ls) ||>
List.fold(fun (prev, listOfLists, currList) t ->
if t < prev then //decreasing, so store your currList and start a new one
t, currList::listOfLists, [t]
else //just add t to your currList
t, listOfLists, t::currList)
let listOfLists = currList::listOfLists //cleanup: append final sublist
let final = List.rev(List.map List.rev listOfLists) //cleanup: reverse everything
printfn "%A" final
Note you'll have to clean up, adding the final list to the list-of-lists, and then reversing the full list-of-lists and each sublist once you've done the fold.

Remove list element occur only once

I have a list in erlang containing interger values.
I want to remove values that occur only one time.(Not Duplicates).
Input = [1,3,2,1,2,2]
Output = [1,2,1,2,2]
I am newbie to erlang. I have tried an approach to sorting them first using list:sort() and then removing a member if the member next to it is the same.
I am having trouble trying to iterate the list. It would be great help if you can show me how I can do it.
multiple(L) ->
M = L -- lists:usort(L),
[X || X <- L , lists:member(X,M)].
Use map to count values and then filter values which was not present just once.
-module(test).
-export([remove_unique/1]).
remove_unique(L) ->
Count = lists:foldl(fun count/2, #{}, L),
lists:filter(fun(X) -> maps:get(X, Count) =/= 1 end, L).
count(X, M) ->
maps:put(X, maps:get(X, M, 0) + 1, M).
And test:
1> c(test).
{ok,test}
2> test:remove_unique([1,2,3,3,3,5,5,6,7,7]).
[3,3,3,5,5,7,7]
3> test:remove_unique([1,2,3,3,3,5,5,6,7,8]).
[3,3,3,5,5]
4> test:remove_unique([1,3,2,1,2,2]).
[1,2,1,2,2]
Here's a solution I'd written when first seeing the question when posted, that uses the same logic as #A.Sarid's recursion/pattern matching answer, except that I use a "Last" parameter instead of the count.
-module(only_dupes).
-export([process/1]).
process([]) -> [];
process(L) when is_list(L) ->
[H|T] = lists:sort(L),
lists:sort(process(undefined, H, T, [])).
process(Last, Curr, [], Acc)
when Curr =/= Last ->
Acc;
process(_Last, Curr, [], Acc) ->
[Curr | Acc];
process(Last, Curr, [Next | Rest], Acc)
when Curr =/= Last, Curr =/= Next ->
process(Curr, Next, Rest, Acc);
process(_Last, Curr, [Next | Rest], Acc) ->
process(Curr, Next, Rest, [Curr | Acc]).
One way for iterating a list (that as a result will return a new list) is using recursion and pattern matching.
After you sort your list you want to iterate the list and to check not only that it is different from the next element, but that there was no other equal elements before it. Consider the list [3,3,3,5,5] if you will only check the next element, the last 3 will also be unique and that is incorrect.
Here is a working program, I used a counter to cover the above case as well. See the syntax for using [H|T] for iterating over the list. You may see more cases and read more about it here.
-module(test).
-export([remove_unique/1]).
remove_unique(Input) ->
Sorted = lists:sort(Input),
remove_unique(Sorted, [], 0).
% Base case - checks if element is unique
remove_unique([H|[]],Output,Count) ->
case Count of
0 -> Output;
_Other -> [H|Output]
end;
% Count is 0 - might be unique - check with next element
remove_unique([H1|[H2|T]],Output, 0)->
case (H1 =:= H2) of
true -> remove_unique([H2|T],[H1|Output],1);
false -> remove_unique([H2|T],Output,0)
end;
% Count is > 0 - not unique - proceed adding to list until next value
remove_unique([H1|[H2|T]],Output,Count) ->
case (H1 =:= H2) of
true -> remove_unique([H2|T],[H1|Output],Count+1);
false -> remove_unique([H2|T],[H1|Output],0)
end.
Test
7> test:remove_unique([1,2,3,3,3,5,5,6,7,7]).
[7,7,5,5,3,3,3]
8> test:remove_unique([1,2,3,3,3,5,5,6,7,8]).
[5,5,3,3,3]

Update list's values

I have the following setup:
1> rd(rec, {name, value}).
rec
2> L = [#rec{name = a, value = 1}, #rec{name = b, value = 2}, #rec{name = c, value = 3}].
[#rec{name = a,value = 1},
#rec{name = b,value = 2},
#rec{name = c,value = 3}]
3> M = [#rec{name = a, value = 111}, #rec{name = c, value = 333}].
[#rec{name = a,value = 111},#rec{name = c,value = 333}]
The elements in list L are unique based on their name. I also don't know the previous values of the elements in list M. What I am trying to do is to update list L with the values in list M, while keeping the elements of L that are not present in M. I did the following:
update_values([], _M, Acc) ->
Acc;
update_attributes_from_fact([H|T], M, Acc) ->
case [X#rec.value || X <- M, X#rec.name =:= H#rec.name] of
[] ->
update_values(T, M, [H|Acc]);
[NewValue] ->
update_values(T, M, [H#rec{value = NewValue}|Acc])
end.
It does the job but I wonder if there is a simpler method that uses bifs.
Thanks a lot.
There's no existing function that does this for you, since you just want to update the value field rather than replacing the entire record in L (like lists:keyreplace() does). If both L and M can be long, I recommend that if you can, you change L from a list to a dict or gb_tree using #rec.name as key. Then you can loop over M, and for each element in M, look up the correct entry if there is one and write back the updated record. The loop can be written as a fold. Even if you convert the list L to a dict first and convert it back again after the loop, it will be more efficient than the L*M approach. But if M is always short and you don't want to keep L as a dict in the rest of the code, your current approach is good.
Pure list comprehensions solution:
[case [X||X=#rec{name=XN}<-M, XN=:=N] of [] -> Y; [#rec{value =V}|_] -> Y#rec{value=V} end || Y=#rec{name=N} <- L].
little bit more effective using lists:keyfind/3:
[case lists:keyfind(N,#rec.name,M) of false -> Y; #rec{value=V} -> Y#rec{value=V} end || Y=#rec{name=N} <- L].
even more effective for big M:
D = dict:from_list([{X#rec.name, X#rec.value} || X<-M]),
[case dict:find(N,D) of error -> Y; {ok,V} -> Y#rec{value=V} end || Y=#rec{name=N} <- L].
but for really big M this approach can be fastest:
merge_join(lists:keysort(#rec.name, L), lists:ukeysort(#rec.name, M)).
merge_join(L, []) -> L;
merge_join([], _) -> [];
merge_join([#rec{name=N}=Y|L], [#rec{name=N, value=V}|_]=M) -> [Y#rec{value=V}|merge_join(L,M)];
merge_join([#rec{name=NL}=Y|L], [#rec{name=NM}|_]=M) when NL<NM -> [Y|merge_join(L,M)];
merge_join(L, [_|M]) -> merge_join(L, M).
You could use lists:ukeymerge/3:
lists:ukeymerge(#rec.name, M, L).
Which:
returns the sorted list formed by merging TupleList1 and TupleList2.
The merge is performed on the Nth element of each tuple. Both
TupleList1 and TupleList2 must be key-sorted without duplicates prior
to evaluating this function. When two tuples compare equal, the tuple
from TupleList1 is picked and the one from TupleList2 deleted.
A record is a tuple and you can use #rec.name to return the position of the key in a transparent way. Note that I reverted the lists L and M, since the function keeps the value from the first list.

what is wrong with my unpair implementation?

I'm trying to figure out WHY i'm getting the error below more than I am interested in a correct implementation of my method.
I have the following f# code that is supposed to unpair a list of tuples into a list containing all the items in the tuples like so:
let unpair l =
let rec loop acc l =
match l with
| [] -> acc
| (x,y)::tl ->
loop (acc # x # y) tl
loop [] l
//should print:
// [1 2 3 4 5 6]
printf "["
List.iter (printf "%A") (unpair [(1, 2); (3, 4); (5, 6)])
printfn "]"
I get the following error for each of my ints when calling unpair:
This expression was expected to have type 'a list but here has type int
Why is it expecting 'a list?
The problem is in the following expression
acc # x # y
The # is used to combine list values together yet here x and y are typed to int. What you're looking for is the :: operator which will add items to a list. Additionally you are building up the list backwards in that expression. Use the following and it should fix your issue
x :: y :: acc
As JaredPar explains, you need to use x::acc to add elements to the accumulator. If you want to append elements to the end, you could write acc # [x], but that's very inefficient, as it needs to copy the whole list for every single element.
The usual solution is to add elements to the front and then reverse the list at the end of the processing:
let unpair l =
let rec loop acc l =
match l with
| [] -> List.rev acc // NOTE: Reverse the list here
| (x,y)::tl ->
loop (y::x::acc) tl // Add elements to the front
loop [] l
This is a lot more efficient than using acc # [x], because it keeps adding elements to the front (which takes just a small constant time) and then creates a single copy of the whole list at the end.
The same function can be also nicely & efficiently implemented using sequence expressions:
let unpair l =
[ for x, y in l do
yield x
yield y ]

Resources