Search code examples
pythongraph

Remove a single element from python's random.sample population


I am trying to implement a graph representation where each node of the graph has random edges to other nodes but not to itself. Therefore, I am trying to exclude the node itself from the population out of which random.sample would generate the random neighbors. However, the following code returns "TypeError: Population must be a sequence. For dicts or sets, use sorted(d)."

import random as rnd
gsize=5
graph = [rnd.sample(list(range(gsize)).remove(node), rnd.randint(0, gsize-1)) for node in range(gsize)]

I saw in this question it was suggested to create a variable first and then apply remove() to it. I tried to refactor it this way

glist = list(range(gsize))
graph = [rnd.sample(glist.remove(node), rnd.randint(0, gsize-1)) for node in range(gsize)]

but now it throws "TypeError: 'NoneType' object is not iterable". I think the problem is essentially the same, i.e. the population is of type NoneType. Is there a neat way of achieving what I need?


Solution

  • list.remove is an in-place operation and thus returns None. What you probably want is something like:

    graph = [
        rnd.sample(
           [other for other in range(gsize) if not node == other], 
           rnd.randint(0, gsize-1)
        ) for node in range(gsize)
    ]
    

    Where you are building a non-inclusive set every time.

    A more efficient way would be:

    from collections import deque
    import random as rnd
    
    graph = []
    
    population = deque(range(gsize))
    
    for _ in range(gsize):
        # pop the rightmost element
        removed = population.pop()
    
        # build the graph with the remaining population
        graph.append(rnd.sample(population, rnd.randint(0, gsize-1)))
    
        # add the removed element to the leftmost side
        population.appendleft(removed)