Bat
Bat

Reputation: 155

Split list into randomised ordered sub lists

I would like to improve the below code to split a list of values into two sub lists, which have been randomised and sorted. The below code works, but I'm sure there is a better/cleaner way to do it.

import random

data = list(range(1, 61))
random.shuffle(data)
Intervention = data[:30]
Control = data[30:]
Intervention.sort()
Control.sort()

f = open('Randomised_Groups.txt', 'w')
f.write('Intervention Group = ' + str(Intervention) + '\n' + 'Control Group = ' + str(Control))
f.close()

The expected output is:

Intervention = [1,3,7,9]

Control = [2,4,5,6,8,10]

Upvotes: 0

Views: 51

Answers (3)

3UqU57GnaX
3UqU57GnaX

Reputation: 399

I think your code is short and clean already. Some changes you can make:

  1. Call sorted() when you slice it.

Intervention = sorted(data[:30])

  1. You can also define both Intervention and Control on one line:

Intervention, Control = data[:30], data[30:]

  1. I would replace the 30 with a variable:

half = len(data)//2

  1. It is safer to open a file with with. That closes the file automatically when indentation stops.
with open('Randomised_Groups.txt', 'w') as f:
    ...
  1. With the use of f-strings you can make the write statement shorter:
f.write(f'Intervention Group = {Intervention} \nControl Group = {Control}')

All combined:

import random

data = list(range(1, 61))
random.shuffle(data)
half = len(data)//2
Intervention, Control = sorted(data[:half]), sorted(data[half:])

with open('Randomised_Groups.txt', 'w') as f:
    f.write(f'Intervention Group = {Intervention}\nControl Group = {Control}')

Upvotes: 1

Here is another solution that is more dynamic using built in random functionality that only creates the lists needed (no extra memory) and would work with lists that contain any type of object (provided that object can be sorted):

import random
def convert_to_random_list(data, num_list):
    """
    Takes in the data as one large list and converts it into
    [num_list] random sorted lists.
    """
    result_lists = [list() for _ in range(num_list)] # two lists
    for x in data:
        # Using randint we pick which list to insert into
        result_lists[random.randint(0, num_list - 1)].append(x)
    # You could use list comprehension here with `sorted(...)` but it would take a little extra memory.
    for _list in result_lists: 
        _list.sort()
    return result_lists

Can be tested with:

data = list(range(1, 61))
random.shuffle(data)
temp = convert_to_random_list(data, 3)
print(temp)

Upvotes: 0

Hoog
Hoog

Reputation: 2298

Something like this might be what you want:

import random

my_rng = [random.randint(0,1) for i in range(60)]

Control = [i for i in range(60) if my_rng[i] == 0]
Intervention = [i for i in range(60) if my_rng[i] == 1]

print(Control)

The idea is to create 60 random 1s or 0s to use as indicators for which list to put each number in. This will only work if you do not need the two lists to be the same length. To get the same length would require changing how my_rng is created in this example.

I have tinkered a bit further and got the lists of the same length:

import random

my_rng = [0 for i in range(30)]
my_rng.extend([1 for i in range(30)])
random.shuffle(my_rng)
Control = [i for i in range(60) if my_rng[i] == 0]
Intervention = [i for i in range(60) if my_rng[i] == 1]

Here, instead of adding randomly 1 or 0 to my_rng I get a list of 30 0s and 30 1s to shuffle, then continue like before.

Upvotes: 1

Related Questions