'Randomly selecting values from a dictionary and assigning them to a new dictionary

I have a huge list of file paths that I'm trying to organize for a project. I have sorted these file paths into three categories (colors red, green, and blue) and put them into a dictionary. Now I want to randomly select 9 of these file paths (3 from each category) and sort them into a secondary, smaller dictionary. This is the code I have used so far to select the file paths and I've printed them just to check over the output.

counter = 0
while counter < 3:
    files = [random.choice(i) for i in colors.values()]
    counter += 1
    print(files)

From this, I get 3 lists each one containing one of each category. What I need to do now is sort them into a new dictionary:

newDict = {blue1: [], 
           red1: [], 
           green1: [], 
           blue2: [], 
           red2: [], 
           green2: [], 
           blue3: [],  
           red3: [], 
           green3: []}

...so that there is one file per key and the file is in the relevant category still. Any advice on how I might be able to do this? Thanks in advance!



Solution 1:[1]

First I'd like to convert:

counter = 0
while counter < 3:
    files = [random.choice(i) for i in colors.values()]
    counter += 1
    print(files)

to:

for _ in range(3):
    files = [random.choice(i) for i in colors.values()]
    print(files)

or even to:

files = [random.choices(files, k=3) for files in colors.values()]
print(files)

Now you want to store them back, first thing is to remember the colors:

files = [(color, random.choices(files, k=3)) for color, files in colors.items()]
print(files)

Now you can go imperatively:

final_dict = {}
for color, three_files in files:
    for i, file in enumerate(three_files, start=1):
        final_dict[f"{color}{i}"] = file

Or merge the two steps, no needs for a files temporary name:

final_dict = {}
for color, files in colors.items():
    for i, file in enumerate(random.choices(files, k=3), start=1):
        final_dict[f"{color}{i}"] = file

But while we're at it we can also do it using a dictionary comprehension:

final_dict = {
    f"{color}{i}": file
    for color, files in colors.items()
    for i, file in enumerate(random.choices(files, k=3), start=1)
}

Solution 2:[2]

EDITED:

This should work, and avoid repetitions. I'm checking if there are enough new files left for each color, if not the selection stops:

colors = {'red': ['file_00', 'file_01', 'file_02', 'file_05'],
      'blue': ['file_06', 'file_08', 'file_09', 'file_10'],
      'green': ['file_14', 'file_15']}

newDict = {}

for i in range(3):

    # check if there are still file names for each color
    if any(len(lst) == 0 for lst in colors.values()):
        print('Not enough files left!')
        break

    for color, file_names_list in colors.items():
        selected_file = random.choice(file_names_list)
        newDict[f'{color}_{i}'] = selected_file
        # removing the selected file from the list, so you won't select it again
        file_names_list.remove(selected_file)

# just printing the result
for k, v in newDict.items():
    print(k, ":", v)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Julien Palard
Solution 2