Erlang list comprehension, once again - erlang

I'm trying to get a list comprehension working, which intention is to verify that each element X in List is followed by X+Incr (or an empty list). Later, I shall use that list and compare it with a list generated with lists:seq(From,To,Incr).
The purpose is to practice writing test cases and finding test properties.
I've done the following steps:
1> List.
[1,3,5,8,9,11,13]
2> Incr.
2
3> List2=[X || X <- List, (tl(List) == []) orelse (hd(tl(List)) == X + Incr)].
[1]
To me, it seem that my list comprehension only takes the first element in List, running that through the filter/guards, and stops, but it should do the same for EACH element in List, right?
I would like line 3 returning a list, looking like: [1,2,9,11,13].
Any ideas of how to modify current comprehension, or change my approach totally?
PS. I'm using eqc-quickcheck, distributed via Quviq's webpage, if that might change how to solve this.

The problem with your list comprehension is that List always refers to the entire list. Thus this condition allows only those X that are equal to the second element of List minus Incr:
(hd(tl(List)) == X + Incr)
The second element is always 3, so this condition only holds for X = 1.
A list comprehension cannot "look ahead" to other list elements, so this should probably be written as a recursive function:
check_incr([], _Incr) ->
true;
check_incr([_], _Incr) ->
true;
check_incr([A, B | Rest], Incr) ->
A + Incr == B andalso check_incr([B | Rest], Incr).

Maybe I'm misunderstanding you, but a list comprehension is supposed to be "creating a list based on existing lists". Here's one way to generate your list using a list comprehension without using lists:seq:
> Start = 1, Inc = 2, N = 6.
6
> [Start + X*Inc || X <- lists:seq(0,N)].
[1,3,5,7,9,11,13]

You could do something like this:
> lists:zipwith(fun (X, Y) -> Y - X end, [0 | List], List ++ [0]).
[1,2,2,2,2,2,2,-13]
Then check that all elements are equal to Incr, except the first that should be equal to From and the last that should be greater or equal than -To.

One quick comment is that the value List does NOT change when in the comprehension is evaluated, it always refers to the initial list. It is X which steps over all the elements in the list. This means that your tests will always refer to the first elements of the list. As a list comprehension gives you element of a list at a time it is generally not a good tool to use when you want to compare elements in the list.
There is no way with a list comprehension to look at successive sublists which is what you would need (like MAPLIST in Common Lisp).

Related

List Cons-Into Function?

I am often wanting to take one list and cons every element into an existing list.
MyList = [3,2,1],
MyNewElements = [4,5,6],
MyNewList = lists:foldl(fun(A, B) -> [A | B] end, MyList, MyNewElements).
%% [6,5,4,3,2,1]
Assuming MyList has 1M elements and MyNewElements only has a few, I want to do this efficiently.
I couldn't figure out which of these functions- if any- did what I was trying to do:
https://www.erlang.org/doc/man/lists.html
Adding a short list to the beginning of a long list is cheap - the execution time of the ++ operator is proportional to the length of the first list. The first list is copied, and the second list is added as the tail without modification.
So in your example, that would be:
lists:reverse(MyNewElements) ++ MyList
(The execution time of lists:reverse/1 is also proportional to the length of the argument.)
Another option, aside from those already provided, would be just to have
NewDeepList = [MyList | DeepList]
and modify the reading/traversing to be able to handle [[element()]] instead of [element()].
Because erlang is function language and is different from c, javascript, it copy variable and modify it, not just modify it. Therefore it is impossible compression to o(A).length(A) is length of new added elements.

Take every item in list that starts with x and put it in a new list - Rego

list := ["a:aqsdf", "a:asdf", "b:gfs", "b:sdf", "a:adfd", "b:asdfd"]
I want the new list to only include items that start with 'a': ["a:aqsdf", "a:asdf", "a:adfd"]
I've tried working with sets with no success. This would be a breeze in python but can't seem to wrap my head around rego. I can turn it into a set but not sure how to squeeze in an if statement(startswith(list[_], "a") == true)
One way to do this is with an array comprehension and the startswith builtin function:
[ x | x := list[_]; startswith(x, "a")]
Playground example: https://play.openpolicyagent.org/p/8mQYYvUL2h
This is essentially saying to define a new array containing the value of x if the rule body is true. The rule body for the comprehension is in turn iterating over all indicies of list for values of x, and will be true when the value of x starts with "a".
References:
https://www.openpolicyagent.org/docs/latest/policy-reference/#strings
https://www.openpolicyagent.org/docs/latest/policy-language/#comprehensions

Removing symmetric pairs using a list comprehension (using notin in a list comprehension)

I have this function where I remove symmetrics pairs from a list relation, works fine but I was curious if it would be possible to rewrite this to a list comprehension.
lrel[str,str] newClonePairs = [];
for (tuple[str L, str R] pair <- clonePairs) {
if (<pair.R, pair.L> notin newClonePairs) {
newClonePairs += pair;
}
}
return newClonePairs;
I got this far (see code below), but how do you then write the notin part? Is there some kind of keyword which can be used to refer to the current list?
return [pair | tuple[tuple[node,loc] L,tuple[node,loc] R] pair <- clonePairs, <pair.R, pair.L> notin thisCurrentList];
The list you are generating can not be referred to during a list comprehension. With a reducer you could, but I don't think it would be very fast.
How about this one:
[ <L, R> | [*_, <L,R>, *post] := clonePairs, <R,L> notin post ]
It will loop through all <L,R> pairs, and add only the ones which are not found in the rest of the list.
It works via "list matching". A list pattern can contain variables with a * in front which will match a sub-list of any length (including the empty list). Such a match is usually not unique (for example above the <L,R> in the middle can be anywhere in the list because *_ and *post can be of any length). If a list pattern can match a list in many ways, then it becomes a generator and the := will loop through all the matches from left to right similar to the behaviour of <-. See also: http://tutor.rascal-mpl.org/Rascal/Rascal.html#/Rascal/Patterns/Abstract/List/List.html

Erlang - How to print list results on a new line?

I have the following function where it takes a list of integers and returns only the even numbers within that list.
even_print(List)->
[X||X <- List, even == even_odd(X)].
How can I print the results in a new line like this:
216> seq_erlang:even_print([2,4,5]).
2
4
instead of this:
216> seq_erlang:even_print2([2,4,5]).
[2,4]
I have used io:format("~p~n",X) inside my list comprehension but my variable X becomes unbound of course.
even_print(List)->
[io:format("Printing ~p ~n",[X])|| X <- List, even == even_odd(X)].
Now try:
217> seq_erlang:even_print([2,4,5]).
Printing 2
Printing 4
[ok,ok]

Find all possible pairs between the subsets of N sets with Erlang

I have a set S. It contains N subsets (which in turn contain some sub-subsets of various lengths):
1. [[a,b],[c,d],[*]]
2. [[c],[d],[e,f],[*]]
3. [[d,e],[f],[f,*]]
N. ...
I also have a list L of 'unique' elements that are contained in the set S:
a, b, c, d, e, f, *
I need to find all possible combinations between each sub-subset from each subset so, that each resulting combination has exactly one element from the list L, but any number of occurrences of the element [*] (it is a wildcard element).
So, the result of the needed function working with the above mentioned set S should be (not 100% accurate):
- [a,b],[c],[d,e],[f];
- [a,b],[c],[*],[d,e],[f];
- [a,b],[c],[d,e],[f],[*];
- [a,b],[c],[d,e],[f,*],[*];
So, basically I need an algorithm that does the following:
take a sub-subset from the subset 1,
add one more sub-subset from the subset 2 maintaining the list of 'unique' elements acquired so far (the check on the 'unique' list is skipped if the sub-subset contains the * element);
Repeat 2 until N is reached.
In other words, I need to generate all possible 'chains' (it is pairs, if N == 2, and triples if N==3), but each 'chain' should contain exactly one element from the list L except the wildcard element * that can occur many times in each generated chain.
I know how to do this with N == 2 (it is a simple pair generation), but I do not know how to enhance the algorithm to work with arbitrary values for N.
Maybe Stirling numbers of the second kind could help here, but I do not know how to apply them to get the desired result.
Note: The type of data structure to be used here is not important for me.
Note: This question has grown out from my previous similar question.
These are some pointers (not a complete code) that can take you to right direction probably:
I don't think you will need some advanced data structures here (make use of erlang list comprehensions). You must also explore erlang sets and lists module. Since you are dealing with sets and list of sub-sets, they seems like an ideal fit.
Here is how things with list comprehensions will get solved easily for you: [{X,Y} || X <- [[c],[d],[e,f]], Y <- [[a,b],[c,d]]]. Here i am simply generating a list of {X,Y} 2-tuples but for your use case you will have to put real logic here (including your star case)
Further note that with list comprehensions, you can use output of one generator as input of a later generator e.g. [{X,Y} || X1 <- [[c],[d],[e,f]], X <- X1, Y1 <- [[a,b],[c,d]], Y <- Y1].
Also for removing duplicates from a list of things L = ["a", "b", "a"]., you can anytime simply do sets:to_list(sets:from_list(L)).
With above tools you can easily generate all possible chains and also enforce your logic as these chains get generated.

Resources