Random selection of contiguous elements in an array in Python

I have a list of indexes, for example. 0 ... 365, and I want to select several, randomly selected without replacement, adjacent subregions of this list.

index = [i+1 for i in range(365) ] 
#n could be 3
for i in range(n):
   exclusion_regions.append( get_random_contiguous_region(index) )

Does anyone have any suggestions for implementing get_random_contiguous_region ()

+4
source share
4 answers

We need a while loop to make sure that we do not overlap the overlap, and you can verify that the slice length matches any other criteria using the comp list, you cannot specify different criteria: If you want random fragments from 5 to 15 percent of the total list size and sample size of about 30 percent:

from random import choice
from numpy import arange

index = [i + 1 for i in range(365)]
choices = []
seen = set()
ar = arange(0.05,.16, .01)
ln = len(index)
sample_size = 0
while sample_size < ln * .30:
    perc = choice(ar)  # get random 5, 10, 15 percent slices
    size = int(ln * perc)
    ch = choice(index[:-size+1]) # avoid falling off the side
    rn = index[ch:ch+size]
    if len(rn) == size and not seen.intersection(rn):
        seen.update(rn)
        choices.append(rn)
        sample_size += len(rn)
print(choices)
+1

:

import random

n = 3
index = [i+1 for i in range(10) ] 
slices = sorted(random.sample(range(0, len(index)), 2*n))
[index[start:end] for start, end in zip(slices[::2], slices[1::2])]
+2

, , .

( , , , , , , .)


: , 0-, . , , .


import random

def range_intersection(a, b):
    if a.step == b.step == 1:
        return range(max(a.start, b.start), min(a.stop, b.stop), 1)
    else:
        # here be dragons!
        raise NotImplemented

def random_subrange(length, range_):
    start = random.randrange(
        range_.start,
        range_.stop - length * range_.step,
        range_.step
    )
    stop = start + length * range_.step
    return range(start, stop, range_.step)

def const_fn(n):
    def fn():
        return n
    return fn

def random_distinct_subranges(num, length, range_):
    if not callable(length):
        length = const_fn(length)
    ranges = []
    for n in range(num):
        while True:
            new_range = random_subrange(length(), range_)
            if not any(range_intersection(new_range, r) for r in ranges):
                ranges.append(new_range)
                break
    ranges.sort(key = lambda r: r.start)
    return ranges

days = range(1, 366)

# pick 3 periods randomly without overlapping
periods = random_distinct_subranges(3, lambda:random.randint(5,15), days)
print(periods)

-

[range(78, 92), range(147, 155), range(165, 173)]

from itertools import chain

rand_days = chain(*periods)
print(list(rand_days))

[78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 147, 148, 149, 150, 151, 152, 153, 154, 165, 166, 167, 168, 169, 170, 171, 172]
+1

: . .

indexes = range(1, 80)
from random import randint, sample 

# recursive division of the sequence
def get_random_division(lst, minsize, maxsize):
    split_index = randint(minsize, maxsize)
    # if the remaining list would get too small, return the unsplit one
    if minsize>len(lst)-split_index:
        return [lst]
    return [lst[:split_index]] + get_random_division(lst[split_index:], minsize, maxsize)

# determine size range of the subdivisions
minsize, maxsize = 5, int(0.15*len(data))
# choose three of the subdivided sequences
sample(get_random_division(indexes, minsize, maxsize), 3)

:

[[17, 18, 19, 20, 21, 22, 23, 24, 25, 26],
 [36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46],
 [1, 2, 3, 4, 5]]
+1

All Articles