pythonalgorithmset-comprehension

Set comprehension and different comparable relations


I have set objects which are comparable in some way and I want to remove objects from the set. I thought about how this problem changes, for different comparable relations between the elements. I was interested in the development of the search space, the use of memory and how the problem scales.

I can do the following, not removing elements:

a_set = set([4,2,3,7,9,16])

def compare(x, y):
    if (x % y == 0) and not (x is y):
        return True
    return False

def list_solution():
    out = set()
    for x in a_set:
        for y in a_set:
            if compare(x,y):
                out.add(x)
                break
    result = a_set-out
    print(result)

    

Of course, my first question as a junior Python programmer would be:


Solution

  • I will precede with confirming your claim - changing set while iterating it would trigger a RuntimeError, which would claim something along the lines of "Set changed size during iteration".


    Now, lets start from the compare function: since you are using sets, x is y is probably like x == y and the last one is always a better choice when possible.

    Furthermore, no need for the condition; you are already performing one:

    def compare (x, y):
        return x != y and x % y == 0
    

    Now to the set comprehension - that's a messy one. After setting the set as an argument - which is better than using global variable - the normal code would be something like

    for x in my_set:
        for y in my_set:
            if compare(x, y):
                for a in (x, y):
                    temp.append(a)
    

    notice the last two lines, which do not use unpacking because that would be impossible in the comprehension. Now, all what's left is to move the a to the front and make all : disappear - and the magic happens:

    def list_solution (my_set):
        return my_set - {a for x in my_set for y in my_set if compare(x, y) for a in (x, y)}
    

    you can test it with something like

    my_set = set([4, 2, 3, 7, 9, 16])
    print(list_solution(my_set)) # {7}
    

    The change for the second case is minor - merely using x instead of the x, y unpacking:

    def list_solution_2 (my_set):
        return my_set - {x for x in my_set for y in my_set if compare(x, y)}