Reputation: 2043
I need to generate a list with unique elements
parties = ['Party A', 'Party B']
I have tried this
def party_generator(size=1, chars=string.ascii_uppercase):
parties = []
for y in range(2):
party = ''.join(random.choice(chars) for x in range(size))
parties.append(''.join(['Party ', party]))
return parties
But I am afraid that my code might generate duplicates
party_generator()
['Party S', 'Party S']
How do I generate a list with unique elements?
Upvotes: 3
Views: 105
Reputation: 1121406
Use a set
to track if you've seen the same generated random string before:
def party_generator(size=1, chars=string.ascii_uppercase):
parties = []
seen = set()
while len(parties) < 2:
party = ''.join(random.choice(chars) for x in range(size))
if party in seen:
continue
seen.add(party)
parties.append('Party {}'.format(party))
return parties
This will continue to generate random strings until you have 2 unique values.
You cannot easily use random.sample()
here as that requires a fixed set of choices to sample from but you are generating names of a variable length. It is possible to build an object that emulates a sequence (by giving it __len__
and __getattr__
methods) and generating a specific word of length size
from all possible words you can create given the chars
variable:
class CharacterRange(object):
def __init__(self, chars, size):
self.chars, self.size = chars, size
def __len__(self):
return len(self.chars) ** self.size
def __getitem__(self, item):
if item < 0:
item = len(self) + item
if not 0 <= item <= len(self):
raise IndexError('Index out of range')
result = []
for i in range(self.size):
item, index = divmod(item, len(self.chars))
result.append(self.chars[index])
return ''.join(result[::-1])
Demo:
>>> uppercase_len1 = CharacterRange(string.uppercase, 1)
>>> len(uppercase_len1)
26
>>> uppercase_len5[0]
'A'
>>> uppercase_len5[-1]
'Z'
>>> uppercase_len1[10]
'K'
>>> uppercase_len1[24]
'Y'
>>> uppercase_len5 = CharacterRange(string.uppercase, 5)
>>> len(uppercase_len5)
11881376
>>> uppercase_len5[0]
'AAAAA'
>>> uppercase_len5[-1]
'ZZZZZ'
>>> uppercase_len5[1024]
'AABNK'
>>> uppercase_len5[1355453]
'CZDCV'
You can pass this object to random.sample()
:
>>> import random
>>> random.sample(uppercase_len5, 5)
['CUSQB', 'UUUWM', 'MKOFI', 'MYROU', 'AHRWA']
producing N words of length K in linear time and constant memory.
and you could simplify your code to:
def party_generator(size=1, chars=string.ascii_uppercase):
return ['Party {}'.format(party) for party in random.sample(CharacterRange(chars, size))]
However, I do think that that would be a little overkill here for just 2 random words.
Upvotes: 2