While the answer of Martijn Pieters is correct, it does slow down when samplesize
becomes large, because using list.insert
in a loop may have quadratic complexity.
Here’s an alternative that, in my opinion, preserves the uniformity while increasing performance:
def iter_sample_fast(iterable, samplesize):
results = []
iterator = iter(iterable)
# Fill in the first samplesize elements:
try:
for _ in xrange(samplesize):
results.append(iterator.next())
except StopIteration:
raise ValueError("Sample larger than population.")
random.shuffle(results) # Randomize their positions
for i, v in enumerate(iterator, samplesize):
r = random.randint(0, i)
if r < samplesize:
results[r] = v # at a decreasing rate, replace random items
return results
The difference slowly starts to show for samplesize
values above 10000
. Times for calling with (1000000, 100000)
:
- iterSample: 5.05s
- iter_sample_fast: 2.64s