Removing elements that have consecutive dupes in Elixir list - list

I have a list of numbers in Elixir, and I want to remove the duplicates, but only for the consecutive dupes.
For the following input list: [1,1,2,2,1,1,1,1,3,3,2,2].
The result should be: [1,2,1,3,2].

Enum.dedup/1 does exactly what you want: it replaces consecutive duplicate elements with only one instance of it and returns the remaining elements in a list.
iex(1)> Enum.dedup([1, 1, 2, 2, 1, 1, 1, 1, 3, 3, 2, 2])
[1, 2, 1, 3, 2]
This works on all values that compare equal with ===, including maps:
iex(2)> Enum.dedup([%{a: 1}, %{a: 2}, %{a: 2}, %{a: 2}])
[%{a: 1}, %{a: 2}]

Related

Elixir: How to find ALL occurrences of a value from a list of tuples?

Find all occurrences of {1, _}; in other words, all first element values that are 1 from each tuple in the list.
Consider the following input:
[
{1, 0},
{2, 2},
{1, 1},
{11, 1},
{1, 3},
{1, 2},
{13, 1}
]
Expected Output:
[{1,0}, {1,1}, {1,3}, {1,2}]
I tried Enum.find(tl(input), fn x -> elem(x, 0) == elem(hd(input), 0) end), but I realized that Enum.find/2 only returns the first and only one element that matches the criteria or function, which is: {1,1}.
My goal is to find all tuples that contain {1, _}, where the first element must be 1 and the second element can be any value.
Here you can use a comprehension with pattern-matching:
result = for x = {1, _} <- list, do: x
Any x that doesn't match the pattern {1, _} will be filtered out.
See the documentation for for/1 for more information.
You could also use Enum.filter/2 together with the match?/2 macro to achieve the same result:
result = Enum.filter(list, fn x -> match?({1, _}, x) end)
Enum.find/2 is useful when you are looking for a single element, e.g. if you want to find the first entry matching your condition.

Creating [1,2,3...,N] list in Prolog

I'd like to create a predicate arrayLEQ(L,N) that is true when L = [1,2,3,...,N].
I tried to do it recursively:
arrayLEQ(L,N) :- arrayLEQ([],L,1,N).
arrayLEQ(L1,L2,N,N) :- append(L1,[N],L2).
arrayLEQ(L1,L2,F,N) :- Fnext is F+1, append(L1,[F],L1n), arrayLEQ(L1n,L2,Fnext,N).
At first I thought that it will work, but sadly it doesn't.
When I do:
?- arrayLEQ(L,5) I get L = [1,2,3,4,5] which is the right answer, but Prolog is ready to look for another answer, which is not wanted.
Would you mind explaining to me what I did wrong and why Prolog tries to look for another answer to this predicate, even if it doesn't exist.
Let's have a look at tracer after the first query succeed:
?- arrayLEQ(L,5).
L = [1,2,3,4,5].
more
Redo:arrayLEQ([1, 2, 3, 4], _5040, 5, 5)
Call:_5844 is 5+1
Exit:6 is 5+1
Call:lists:append([1, 2, 3, 4], [5], _5854)
Exit:lists:append([1, 2, 3, 4], [5], [1, 2, 3, 4, 5])
Call:...
Call:_5880 is 6+1
Exit:7 is 6+1
Call:lists:append([1, 2, 3, 4, 5], [6], _5890)
Exit:lists:append([1, 2, 3, 4, 5], [6], [1, 2, 3, 4, 5, 6])
Call:arrayLEQ([1, 2, 3, 4, 5, 6], _5040, 7, 5)
Call:_5922 is 7+1
Exit:8 is 7+1
Call:lists:append([1, 2, 3, 4, 5, 6], [7], _5932)
Exit:lists:append([1, 2, 3, 4, 5, 6], [7], [1, 2, 3, 4, 5, 6, 7])
Call:arrayLEQ([1, 2, 3, 4, 5, 6, 7], _5040, 8, 5)
Call:_5970 is 8+1
Exit:9 is 8+1
and so on...
You can see that your program keeps adding element into the list, without stopping. So there are two solutions:
Adding a cut (!): arrayLEQ(L1,L2,N,N):- !, append(L1,[N],L2). It works but maybe (in my opinion) there is a better solution.
When adding an element, you don't check if you have already passed the threshod you set (in this case 5). So you just have to add F < N before doing Fnext is F+1. So: arrayLEQ(L1,L2,F,N) :- F < N, Fnext is F+1, append(L1,[F],L1n), arrayLEQ(L1n,L2,Fnext,N). (personally i prefer this solution)
So the query now (with second solution):
?- arrayLEQ(L,5).
L = [1, 2, 3, 4, 5].
more.
false.
I suggest you to not use append/3 because in this case is not necessary at all and write someting like this:
orderedList(L,N):-
orderedList(L,1,N).
orderedList([N],N,N). %you can add a cut ! here, to avoid further search
orderedList([H|T],C,N):-
C < N,
H is C,
C1 is C+1,
orderedList(T,C1,N).
?- orderedList(L,5).
L = [1, 2, 3, 4, 5]
more
false
Then if you need to return an empty list, wou can add a predicate to handle this case easily... BTW check also the question linked in the comments by #repeat

insert at every nth index of a list

Is there a standard Elixir function that can insert an element at every nth index of a list?
With a function call and return like:
iex> List.insert_at_every([1,2,3,4,5], 2, Enum.random(["apple","banana"]))
[1, 2, "apple", 3, 4, "apple", 5]
NB the solution proposed by #Dogbert is better by all means, I am posting this for the sake of diversity.
To intersperse the list with a constant value, one might use Enum.chunk_every/2 and Enum.intersperse/2:
iex(1)> [1,2,3,4,5]
...(1)> |> Enum.chunk_every(2)
...(1)> |> Enum.intersperse("banana")
...(1)> |> List.flatten
#⇒ [1, 2, "banana", 3, 4, "banana", 5]
This won’t work if you want to use a function to retrieve an element to intersperse on each iteration. In that case you are to implement the interspersion yourself:
iex(2)> [1,2,3,4,5]
...(2)> |> Enum.chunk_every(2)
...(2)> |> Enum.map(& &1 ++ [Enum.random(~w|banana apple|)])
...(2)> |> List.flatten
#⇒ [1, 2, "banana", 3, 4, "apple", 5, "apple"]
The result above always contains a redundant trailing element, it should be shaved off afterwards:
iex(3) > with [_ | result] <- :lists.reverse([1, 2, "banana", 3, 4, "apple", 5, "apple"]) do
...(3)> :lists.reverse(result)
...(3)> end
#⇒ [1, 2, "banana", 3, 4, "banana", 5]
There isn't a built in function for this as far as I know, but this can be done using Enum.with_index and Enum.flat_map. When the remainder of the index and the second argument is the second argument minus 1, we insert the element + the callback into the resulting list, and just the element otherwise. I think it makes more sense that passing 1 as the every argument results in your example list instead of 2. You can simply change every with every - 1 if you want though.
defmodule A do
def insert_at_every(list, every, fun) do
list
|> Enum.with_index
|> Enum.flat_map(fn {x, i} ->
if rem(i, every) == every - 1 do
[x, fun.()]
else
[x]
end
end)
end
end
IO.inspect A.insert_at_every([1, 2, 3, 4, 5], 1, fn -> Enum.random(["apple", "banana"]) end)
IO.inspect A.insert_at_every([1, 2, 3, 4, 5], 2, fn -> Enum.random(["apple", "banana"]) end)
IO.inspect A.insert_at_every([1, 2, 3, 4, 5], 3, fn -> Enum.random(["apple", "banana"]) end)
Output:
[1, "apple", 2, "apple", 3, "banana", 4, "banana", 5, "apple"]
[1, 2, "apple", 3, 4, "apple", 5]
[1, 2, 3, "apple", 4, 5]

How can I pop last repeating item from the list in Groovy?

For example:
Given list: [1, 2, 3, 4, 4, 8, 4]
Choose element, which last duplicate will be removed: 4
Output list: [1, 2, 3, 4, 4, 8]
I tried that way, but it just removes first needed element from list:
def list = [1, 2, 3, 4, 4, 8, 4]
def fruit = list.find { item -> item.equals(4)}
list.remove(fruit) //removes first matching item (one)
println list
I guess init(), last() or maybe toUnique() functions may be useful, but don't know, how to do this..
not sure if this is what you mean, but:
def list = [1, 2, 3, 4, 4, 8, 4]
def toremove = 4
list.remove(list.lastIndexOf(toremove))
assert list == [1, 2, 3, 4, 4, 8]

Check List for an Abstract Quality in Mathematica

I'm working with a list in Mathematica generated by the FactorList function that looks like
t = {{-1, 1}, {q, 1}, {P[41, 42], 1}, {P[41, 43], 1}, {P[42, 43], 1}}
I would like to search through this list, identify which elements in position [i][1] (where i is the position of the ith set in t) are of the form P[a,b] where a,b are integers.
Is there a way to test if an element conforms to the general form P[integer, integer] so that running this test on the value q, element t[[2][1]], would return False and running it on P[41,43] would return True?
For example:
Select[t, Head[#[[1]]] == P &]
returns
(* {{P[41, 42], 1}, {P[41, 43], 1}, {P[42, 43], 1}} *)
Or:
Cases[t, {P[_Integer, _Integer], _}]
returns the same