简体   繁体   中英

How to generate a list with couples of random integers?

I am rather new to Python and NetworkX. I need to create a list similar to Edgelist=[(0,1),(0,3),(1,0),(1,2),(1,4),(2,1),(2,5)] , which elements represent the starting and ending node of an edge (link) that is in turn part of a network.

Rather than setting them manually, I want Python to create the couples you see in the list by randomly selecting the integer values of (start,end) from an assigned range of values (namely, 0, 999 ), which represent the node IDs. Then, I want to make sure that every node ID is included at least once in the series of (start,end) values ( this means that all my nodes will be connected to at least one other node ).

I know I could use random.randint(0, 999) but I don't know how to "nest" it into the creation of a list (perhaps a for loop?). I wish I had some code to show you but this is my first attempt at working with NetworkX!

EDIT

To give you a visual idea of what I mean, here are two images. The first is a regular network (aka lattice), and the second is a random one. The edge list of the first was created manually in order to reproduce a chess table, while the second displays an edge list which is a (manually) shuffled counterpart of the first one. As you see, the nodes are kept in exactly the same locations. Hope this helps a bit more. Thanks! 在此处输入图片说明 在此处输入图片说明

There is a similar answer but for a complete graph on - How to generate a fully connected subgraph from node list using python's networkx module

In your case, using zubinmehta 's answer :

 import networkx import itertools def complete_graph_from_list(L, create_using=None): G = networkx.empty_graph(len(L),create_using) if len(L)>1: if G.is_directed(): edges = itertools.permutations(L,2) else: edges = itertools.combinations(L,2) G.add_edges_from(edges) return G 

You could build the graph as:

S = complete_graph_from_list(map(lambda x: str(x), range(0,1000)))
print S.edges()

Python has inbuilt library called itertools . Sample as below as how you achieve what you mentioned:

import itertools

list = [3, 4, 6, 7]
sublist_length = 2
comb = itertools.combinations(list, sublist_length)

This will return comb as an iterator.

You can do comb.next() to get next element in the iterator or iterate over a for loop to get all results as you wanted as below.

for item in comb:
    print item

which should output:

(3, 4),
(3, 6),
(3, 7),
(4, 6),
(4, 7),
(6, 7),

I hope this will solve your problem.

Here is a networkx command that will create a graph such that each node has exactly one edge:

import networkx as nx
G = nx.configuration_model([1]*1000)

If you look into the guts of it, it does the following which answers your question - each node will appear in exactly one edge.

import random
mylist = random.suffle(range(start,end))
edgelist = []
while mylist:
    edgelist.append((mylist.pop(),mylist.pop()))

You should guarantee that mylist has even length before going through the popping.

random.seed(datetime.datetime.now()) 

from random import randint
# ot generate 100 tuples with randints in range 0-99
li = [(randint(0,99),randint(0,99)) for i in range(100)]
print(li)

[(80, 55), (3, 10), (66, 65), (26, 23), (8, 72), (83, 25), (24, 99), (72, 9), (52, 76), (72, 68), (67, 25), (72, 18), (94, 62), (7, 62), (49, 94), (29, 89), (11, 38), (52, 51), (19, 32), (20, 85), (56, 61), (4, 40), (97, 58), (82, 2), (50, 82), (77, 5), (2, 9), (2, 46), (39, 4), (74, 40), (69, 15), (1, 77), (45, 58), (80, 59), (85, 80), (27, 80), (81, 4), (22, 33), (77, 60), (75, 87), (43, 36), (60, 34), (90, 54), (75, 3), (89, 84), (51, 93), (62, 64), (81, 50), (15, 60), (33, 97), (42, 62), (83, 26), (13, 33), (41, 87), (29, 63), (4, 32), (6, 14), (79, 73), (95, 4), (41, 16), (96, 64), (15, 28), (35, 13), (35, 82), (77, 16), (63, 27), (75, 37), (11, 52), (21, 35), (37, 96), (9, 86), (83, 11), (5, 42), (34, 32), (17, 8), (65, 55), (58, 19), (90, 40), (18, 75), (29, 14), (0, 11), (25, 68), (34, 52), (22, 8), (12, 53), (16, 49), (73, 54), (78, 80), (74, 60), (40, 68), (69, 20), (37, 38), (74, 60), (53, 90), (25, 48), (44, 52), (49, 27), (28, 35), (29, 94), (35, 60)]

For the list creation you can do something like:

import random
max = 999
min = 0
original_values = range(min, max) # could be arbitrary list
n_edges = # some number..
my_edge_list = [(random.choice(original_values), random.choice(original_values)) 
                      for _ in range(n_edges)]

To assert you have all values in there you can do the following

vals = set([v for tup in my_edge_list for v in tup])
assert all([v in vals for v in original_values])

The assert will make sure you have the proper representation in your edges. As far as doing your best to make sure you don't hit that assert you can do a couple of things.

  1. Sample without replacement from your list of integers until they are all gone to create a "base network" and then randomly add on more to your hearts desire
  2. Make n_edges sufficiently high that it's very likely your condition will be met. If it's not try again...

Really depends on what you're going to use the network for and what kind of structure you want it to have

EDIT: I have updated my response to be more robust to an arbitrary list of values rather than requiring a sequential list

Here is a solution that first generates a random population of nodes ( pop1 ), then shuffles it ( pop2 ) and combines those into a list of pairs.

Note: this method only yields vertices where each node is exactly once start and exactly once end , so maybe not what you're after. See below for another method

import random, copy

random.seed() # defaults to time.time() ...
# extract a number of samples - the number of nodes you want
pop1 = random.sample(xrange(1000), 10)
pop2 = copy.deepcopy( pop1 )
random.shuffle( pop2 )
# generate pairs from the same population - this guarantees your constraint
pairs = zip( pop1, pop2 )

print pairs

Output:

[(17, 347), (812, 688), (347, 266), (731, 342), (342, 49), (904, 17), (49, 731), (50, 904), (688, 50), (266, 812)]

Here is another method

This allows for duplicate occurrences of the nodes. The idea is to draw start and end nodes from the same population:

import random
random.seed()
population = range(10) # any population would do
# choose randomly from the population for both ends
# so you can have duplicates
pairs = [(random.choice(population), random.choice(population) for _ in xrange(100)]
print pairs[:10]

Output:

[(1, 9), (7, 1), (8, 6), (4, 7), (6, 2), (7, 3), (0, 2), (1, 0), (8, 3), (8, 3)]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM