Search code examples
rascal

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];

Solution

  • 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