[Python]: generate and array of all possible combinations - python

I have a very straightforward combination problem. I have two arrays (a and b). Array a indicates all the values one of the three slots in array b can take on. Each slot in array b can have a value between 1 and 5. An example of which would be [1, 4, 5]. I would like to generate an array (c) with all possible combinations. I like to extend the basic example larger arrays.
Input:
a = [1, 2, 3, 4, 5]
b = [1, 2, 3]
Output:
c = [[1, 1, 1], [1, 1, 2],[1, 1, 3], [1, 1, 4], [1, 1, 5],
[1, 2, 1], [1, 2, 2],[1, 2, 3], [1, 2, 4], [1, 2, 5],
[1, 3, 1], [1, 3, 2],[1, 3, 3], [1, 3, 4], [1, 3, 5],
[1, 4, 1], [1, 4, 2],[1, 4, 3], [1, 4, 4], [1, 4, 5],
[1, 5, 1], [1, 5, 2],[1, 5, 3], [1, 5, 4], [1, 5, 5],
[2, 1, 1], [2, 1, 2],[2, 1, 3], [2, 1, 4], [2, 1, 5],
[2, 2, 1], [2, 2, 2],[2, 2, 3], [2, 2, 4], [2, 2, 5],
[2, 3, 1], [2, 3, 2],[2, 3, 3], [2, 3, 4], [2, 3, 5],
[2, 4, 1], [2, 4, 2],[2, 4, 3], [2, 4, 4], [2, 4, 5],
[2, 5, 1], [2, 5, 2],[2, 5, 3], [2, 5, 4], [2, 5, 5],
[3, 1, 1], [3, 1, 2],[3, 1, 3], [3, 1, 4], [3, 1, 5],
[3, 2, 1], [3, 2, 2],[3, 2, 3], [3, 2, 4], [3, 2, 5],
[3, 3, 1], [3, 3, 2],[3, 3, 3], [3, 3, 4], [3, 3, 5],
[3, 4, 1], [3, 4, 2],[3, 4, 3], [3, 4, 4], [3, 4, 5],
[3, 5, 1], [3, 5, 2],[3, 5, 3], [3, 5, 4], [3, 5, 5],
[4, 1, 1], [4, 1, 2],[4, 1, 3], [4, 1, 4], [4, 1, 5],
[4, 2, 1], [4, 2, 2],[4, 2, 3], [4, 2, 4], [4, 2, 5],
[4, 3, 1], [4, 3, 2],[4, 3, 3], [4, 3, 4], [4, 3, 5],
[4, 4, 1], [4, 4, 2],[4, 4, 3], [4, 4, 4], [4, 4, 5],
[5, 5, 1], [5, 5, 2],[5, 5, 3], [5, 5, 4], [5, 5, 5],
[5, 1, 1], [5, 1, 2],[5, 1, 3], [5, 1, 4], [5, 1, 5],
[5, 2, 1], [5, 2, 2],[5, 2, 3], [5, 2, 4], [5, 2, 5],
[5, 3, 1], [5, 3, 2],[5, 3, 3], [5, 3, 4], [5, 3, 5],
[5, 4, 1], [5, 4, 2],[5, 4, 3], [5, 4, 4], [5, 4, 5],
[5, 5, 1], [5, 5, 2],[5, 5, 3], [5, 5, 4], [5, 5, 5]]
Solution for the problem above:
d = []
for i in range(len(a)):
for j in range(len(a)):
for k in range(len(a)):
e = []
e.append(i+1)
e.append(j+1)
e.append(k+1)
d.append(e)
I am looking for a more generic way. One which can accommodate larger arrays (see below) without the need to use a nested for loop structure. I searched for a comparable example, but was unable to find one on stackoverflow.
Input:
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

You are looking for itertools.product().
a = [1, 2, 3, 4, 5]
b = 3 # Actually, you just need the length of the array, values do not matter
c = itertools.product(a, repeat=b)
Note that this returns an iterator, you may need to cast it using list() but be aware this can take forever and highly consume memory if the sizes grow.

In the general case, you should of course use the itertools module, in this particular case itertools.product, as explained in the other answer.
If you want to implement the function yourself, you can use recursion to make it applicable to any array sizes. Also, you should probably make it a generator function (using yield instead of return), as the result could be rather long. You can try something like this:
def combinations(lst, num):
if num > 0:
for x in lst:
for comb in combinations(lst, num - 1):
yield [x] + comb
else:
yield []

Related

OpenAI Gym: Walk through all possible actions in an action space

I want to build a brute-force approach that tests all actions in a Gym action space before selecting the best one. Is there any simple, straight-forward way to get all possible actions?
Specifically, my action space is
import gym
action_space = gym.spaces.MultiDiscrete([5 for _ in range(4)])
I know I can sample a random action with action_space.sample() and also check if an action is contained in the action space, but I want to generate a list of all possible action within that space.
Is there anything more elegant (and performant) than just a bunch of for loops? The problem with for loops is that I want it to work with any size of action space, so I cannot hard-code 4 for loops to walk through the different actions.
The actions in a gym environment are usually represented by integers only, this mean if you get the total number of possible actions, then an array of all possible actions can be created.
The way to get the total number of possible actions in a gym environment depends on the type of action space it has, for your case it's a MultiDiscrete action space and thus the attribute nvec can be used as mentioned here by #Valentin Macé like so -:
>> print(env.action_space.nvec)
array([5, 5, 5, 5], dtype=int64)
Note that the attribute nvec stands for n vector, since its output is a multidimensional vector. Also note that the attribute is a numpy array.
Now that we have the array to convert it into a list of lists of actions assuming that since the action_space.sample function returns a numpy array of a random function from each of the dimensions of the MultiDiscrete action_space i.e. -:
>> env.action_space.sample() # This does not return a single action but 4 actions for your case since you have a multi discrete action space of length 4.
array([2, 2, 0, 1], dtype=int64)
So thus to convert the array to a list of lists of possible actions in each dimensions we can use list comprehensions like so -:
>> [list(range(1, (k + 1))) for k in action_space.nvec]
[[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]
Note that this is scalable to any number of dimensions and is also quite efficient performance wise.
Now you can loop over the possible actions in each dimension using only two loops like so -:
possible_actions = [list(range(1, (k + 1))) for k in action_space.nvec]
for action_dim in possible_actions :
for action in action_dim :
# Find best action.....
pass
For more info about the same I would like you to also visit this thread on github, with a somewhat similar issue being discussed incase you find the same useful.
EDIT:
So as per the comment of yours #CGFoX I assume that you want it such that all the possible combination vectors of the actions can be generated as a list for any number of dimensions, somewhat like so -:
>> get_actions()
[[1, 1, 1, 1], [1, 1, 1, 2] ....] # For all possible combinations.
The same can be achieved like so using recursion and with only two loops, this is also expandable to as many dimensions as provided.
def flatten(actions) :
# This function flattens any actions passed somewhat like so -:
# INPUT -: [[1, 2, 3], 4, 5]
# OUTPUT -: [1, 2, 3, 4, 5]
new_actions = [] # Initializing the new flattened list of actions.
for action in actions :
# Loop through the actions
if type(action) == list :
# If any actions is a pair of actions i.e. a list e.g. [1, 1] then
# add it's elements to the new_actions list.
new_actions += action
elif type(action) == int :
# If the action is an integer then append it directly to the new_actions
# list.
new_actions.append(action)
# Returns the new_actions list generated.
return new_actions
def get_actions(possible_actions) :
# This functions recieves as input the possibilities of actions for every dimension
# and returns all possible dimensional combinations for the same.
# Like so -:
# INPUT-: [[1, 2, 3, 4], [1, 2, 3, 4]] # Example for 2 dimensions but can be scaled for any.
# OUTPUT-: [[1, 1], [1, 2], [1, 3] ... [4, 1] ... [4, 4]]
if len(possible_actions) == 1 :
# If there is only one possible list of actions then it itself is the
# list containing all possible combinations and thus is returned.
return possible_actions
pairs = [] # Initializing a list to contain all pairs of actions generated.
for action in possible_actions[0] :
# Now we loop over the first set of possibilities of actions i.e. index 0
# and we make pairs of it with the second set i.e. index 1, appending each pair
# to the pairs list.
# NOTE: Incase the function is recursively called the first set of possibilities
# of actions may contain vectors and thus the newly formed pair has to be flattened.
# i.e. If a pair has already been made in previous generation like so -:
# [[[1, 1], [2, 2], [3, 3] ... ], [1, 2, 3, 4]]
# Then the pair formed will be this -: [[[1, 1], 1], [[1, 1], 2] ... ]
# But we want them to be flattened like so -: [[1, 1, 1], [1, 1, 2] ... ]
for action2 in possible_actions[1] :
pairs.append(flatten([action, action2]))
# Now we create a new list of all possible set of actions by combining the
# newly generated pairs and the sets of possibilities of actions that have not
# been paired i.e. sets other than the first and the second.
# NOTE: When we made pairs we did so only for the first two indexes and not for
# all thus to do so we make a new list with the sets that remained unpaired
# and the paired set. i.e.
# BEFORE PAIRING -: [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]
# AFTER PAIRING -: [[[1, 1], [1, 2] ... ], [1, 2, 3, 4]] # Notice how the third set
# i.e. the index 2 is still unpaired and first two sets have been paired.
new_possible_actions = [pairs] + possible_actions[2 : ]
# Now we recurse the function and call it within itself to make pairs for the
# left out sets, Note that since the first two sets were combined to form a paired
# first set now this set will be paired with the third set.
# This recursion will keep happening until all the sets have been paired to form
# a single set with all possible combinations.
possible_action_vectors = get_actions(new_possible_actions)
# Finally the result of the recursion is returned.
# NOTE: Only the first index is returned since now the first index contains the
# paired set of actions.
return possible_action_vectors[0]
Once we have this function defined it can be used with our previously generated set of possibilities of actions to get all possible combinations like so -:
possible_actions = [list(range(1, (k + 1))) for k in action_space.nvec]
print(get_actions(possible_actions))
>> [[1, 1, 1, 1], [1, 1, 1, 2], [1, 1, 1, 3], [1, 1, 1, 4], [1, 1, 1, 5], `[1, 1, 2, 1], [1, 1, 2, 2], [1, 1, 2, 3], [1, 1, 2, 4], [1, 1, 2, 5], [1, 1, 3, 1], [1, 1, 3, 2], [1, 1, 3, 3], [1, 1, 3, 4], [1, 1, 3, 5], [1, 1, 4, 1], [1, 1, 4, 2], [1, 1, 4, 3], [1, 1, 4, 4], [1, 1, 4, 5], [1, 1, 5, 1], [1, 1, 5, 2], [1, 1, 5, 3], [1, 1, 5, 4], [1, 1, 5, 5], [1, 2, 1, 1], [1, 2, 1, 2], [1, 2, 1, 3], [1, 2, 1, 4], [1, 2, 1, 5], [1, 2, 2, 1], [1, 2, 2, 2], [1, 2, 2, 3], [1, 2, 2, 4], [1, 2, 2, 5], [1, 2, 3, 1], [1, 2, 3, 2], [1, 2, 3, 3], [1, 2, 3, 4], [1, 2, 3, 5], [1, 2, 4, 1], [1, 2, 4, 2], [1, 2, 4, 3], [1, 2, 4, 4], [1, 2, 4, 5], [1, 2, 5, 1], [1, 2, 5, 2], [1, 2, 5, 3], [1, 2, 5, 4], [1, 2, 5, 5], [1, 3, 1, 1], [1, 3, 1, 2], [1, 3, 1, 3], [1, 3, 1, 4], [1, 3, 1, 5], [1, 3, 2, 1], [1, 3, 2, 2], [1, 3, 2, 3], [1, 3, 2, 4], [1, 3, 2, 5], [1, 3, 3, 1], [1, 3, 3, 2], [1, 3, 3, 3], [1, 3, 3, 4], [1, 3, 3, 5], [1, 3, 4, 1], [1, 3, 4, 2], [1, 3, 4, 3], [1, 3, 4, 4], [1, 3, 4, 5], [1, 3, 5, 1], [1, 3, 5, 2], [1, 3, 5, 3], [1, 3, 5, 4], [1, 3, 5, 5], [1, 4, 1, 1], [1, 4, 1, 2], [1, 4, 1, 3], [1, 4, 1, 4], [1, 4, 1, 5], [1, 4, 2, 1], [1, 4, 2, 2], [1, 4, 2, 3], [1, 4, 2, 4], [1, 4, 2, 5], [1, 4, 3, 1], [1, 4, 3, 2], [1, 4, 3, 3], [1, 4, 3, 4], [1, 4, 3, 5], [1, 4, 4, 1], [1, 4, 4, 2], [1, 4, 4, 3], [1, 4, 4, 4], [1, 4, 4, 5], [1, 4, 5, 1], [1, 4, 5, 2], [1, 4, 5, 3], [1, 4, 5, 4], [1, 4, 5, 5], [1, 5, 1, 1], [1, 5, 1, 2], [1, 5, 1, 3], [1, 5, 1, 4], [1, 5, 1, 5], [1, 5, 2, 1], [1, 5, 2, 2], [1, 5, 2, 3], [1, 5, 2, 4], [1, 5, 2, 5], [1, 5, 3, 1], [1, 5, 3, 2], [1, 5, 3, 3], [1, 5, 3, 4], [1, 5, 3, 5], [1, 5, 4, 1], [1, 5, 4, 2], [1, 5, 4, 3], [1, 5, 4, 4], [1, 5, 4, 5], [1, 5, 5, 1], [1, 5, 5, 2], [1, 5, 5, 3], [1, 5, 5, 4], [1, 5, 5, 5], [2, 1, 1, 1], [2, 1, 1, 2], [2, 1, 1, 3], [2, 1, 1, 4], [2, 1, 1, 5], [2, 1, 2, 1], [2, 1, 2, 2], [2, 1, 2, 3], [2, 1, 2, 4], [2, 1, 2, 5], [2, 1, 3, 1], [2, 1, 3, 2], [2, 1, 3, 3], [2, 1, 3, 4], [2, 1, 3, 5], [2, 1, 4, 1], [2, 1, 4, 2], [2, 1, 4, 3], [2, 1, 4, 4], [2, 1, 4, 5], [2, 1, 5, 1], [2, 1, 5, 2], [2, 1, 5, 3], [2, 1, 5, 4], [2, 1, 5, 5], [2, 2, 1, 1], [2, 2, 1, 2], [2, 2, 1, 3], [2, 2, 1, 4], [2, 2, 1, 5], [2, 2, 2, 1], [2, 2, 2, 2], [2, 2, 2, 3], [2, 2, 2, 4], [2, 2, 2, 5], [2, 2, 3, 1], [2, 2, 3, 2], [2, 2, 3, 3], [2, 2, 3, 4], [2, 2, 3, 5], [2, 2, 4, 1], [2, 2, 4, 2], [2, 2, 4, 3], [2, 2, 4, 4], [2, 2, 4, 5], [2, 2, 5, 1], [2, 2, 5, 2], [2, 2, 5, 3], [2, 2, 5, 4], [2, 2, 5, 5], [2, 3, 1, 1], [2, 3, 1, 2], [2, 3, 1, 3], [2, 3, 1, 4], [2, 3, 1, 5], [2, 3, 2, 1], [2, 3, 2, 2], [2, 3, 2, 3], [2, 3, 2, 4], [2, 3, 2, 5], [2, 3, 3, 1], [2, 3, 3, 2], [2, 3, 3, 3], [2, 3, 3, 4], [2, 3, 3, 5], [2, 3, 4, 1], [2, 3, 4, 2], [2, 3, 4, 3], [2, 3, 4, 4], [2, 3, 4, 5], [2, 3, 5, 1], [2, 3, 5, 2], [2, 3, 5, 3], [2, 3, 5, 4], [2, 3, 5, 5], [2, 4, 1, 1], [2, 4, 1, 2], [2, 4, 1, 3], [2, 4, 1, 4], [2, 4, 1, 5], [2, 4, 2, 1], [2, 4, 2, 2], [2, 4, 2, 3], [2, 4, 2, 4], [2, 4, 2, 5], [2, 4, 3, 1], [2, 4, 3, 2], [2, 4, 3, 3], [2, 4, 3, 4], [2, 4, 3, 5], [2, 4, 4, 1], [2, 4, 4, 2], [2, 4, 4, 3], [2, 4, 4, 4], [2, 4, 4, 5], [2, 4, 5, 1], [2, 4, 5, 2], [2, 4, 5, 3], [2, 4, 5, 4], [2, 4, 5, 5], [2, 5, 1, 1], [2, 5, 1, 2], [2, 5, 1, 3], [2, 5, 1, 4], [2, 5, 1, 5], [2, 5, 2, 1], [2, 5, 2, 2], [2, 5, 2, 3], [2, 5, 2, 4], [2, 5, 2, 5], [2, 5, 3, 1], [2, 5, 3, 2], [2, 5, 3, 3], [2, 5, 3, 4], [2, 5, 3, 5], [2, 5, 4, 1], [2, 5, 4, 2], [2, 5, 4, 3], [2, 5, 4, 4], [2, 5, 4, 5], [2, 5, 5, 1], [2, 5, 5, 2], [2, 5, 5, 3], [2, 5, 5, 4], [2, 5, 5, 5], [3, 1, 1, 1], [3, 1, 1, 2], [3, 1, 1, 3], [3, 1, 1, 4], [3, 1, 1, 5], [3, 1, 2, 1], [3, 1, 2, 2], [3, 1, 2, 3], [3, 1, 2, 4], [3, 1, 2, 5], [3, 1, 3, 1], [3, 1, 3, 2], [3, 1, 3, 3], [3, 1, 3, 4], [3, 1, 3, 5], [3, 1, 4, 1], [3, 1, 4, 2], [3, 1, 4, 3], [3, 1, 4, 4], [3, 1, 4, 5], [3, 1, 5, 1], [3, 1, 5, 2], [3, 1, 5, 3], [3, 1, 5, 4], [3, 1, 5, 5], [3, 2, 1, 1], [3, 2, 1, 2], [3, 2, 1, 3], [3, 2, 1, 4], [3, 2, 1, 5], [3, 2, 2, 1], [3, 2, 2, 2], [3, 2, 2, 3], [3, 2, 2, 4], [3, 2, 2, 5], [3, 2, 3, 1], [3, 2, 3, 2], [3, 2, 3, 3], [3, 2, 3, 4], [3, 2, 3, 5], [3, 2, 4, 1], [3, 2, 4, 2], [3, 2, 4, 3], [3, 2, 4, 4], [3, 2, 4, 5], [3, 2, 5, 1], [3, 2, 5, 2], [3, 2, 5, 3], [3, 2, 5, 4], [3, 2, 5, 5], [3, 3, 1, 1], [3, 3, 1, 2], [3, 3, 1, 3], [3, 3, 1, 4], [3, 3, 1, 5], [3, 3, 2, 1], [3, 3, 2, 2], [3, 3, 2, 3], [3, 3, 2, 4], [3, 3, 2, 5], [3, 3, 3, 1], [3, 3, 3, 2], [3, 3, 3, 3], [3, 3, 3, 4], [3, 3, 3, 5], [3, 3, 4, 1], [3, 3, 4, 2], [3, 3, 4, 3], [3, 3, 4, 4], [3, 3, 4, 5], [3, 3, 5, 1], [3, 3, 5, 2], [3, 3, 5, 3], [3, 3, 5, 4], [3, 3, 5, 5], [3, 4, 1, 1], [3, 4, 1, 2], [3, 4, 1, 3], [3, 4, 1, 4], [3, 4, 1, 5], [3, 4, 2, 1], [3, 4, 2, 2], [3, 4, 2, 3], [3, 4, 2, 4], [3, 4, 2, 5], [3, 4, 3, 1], [3, 4, 3, 2], [3, 4, 3, 3], [3, 4, 3, 4], [3, 4, 3, 5], [3, 4, 4, 1], [3, 4, 4, 2], [3, 4, 4, 3], [3, 4, 4, 4], [3, 4, 4, 5], [3, 4, 5, 1], [3, 4, 5, 2], [3, 4, 5, 3], [3, 4, 5, 4], [3, 4, 5, 5], [3, 5, 1, 1], [3, 5, 1, 2], [3, 5, 1, 3], [3, 5, 1, 4], [3, 5, 1, 5], [3, 5, 2, 1], [3, 5, 2, 2], [3, 5, 2, 3], [3, 5, 2, 4], [3, 5, 2, 5], [3, 5, 3, 1], [3, 5, 3, 2], [3, 5, 3, 3], [3, 5, 3, 4], [3, 5, 3, 5], [3, 5, 4, 1], [3, 5, 4, 2], [3, 5, 4, 3], [3, 5, 4, 4], [3, 5, 4, 5], [3, 5, 5, 1], [3, 5, 5, 2], [3, 5, 5, 3], [3, 5, 5, 4], [3, 5, 5, 5], [4, 1, 1, 1], [4, 1, 1, 2], [4, 1, 1, 3], [4, 1, 1, 4], [4, 1, 1, 5], [4, 1, 2, 1], [4, 1, 2, 2], [4, 1, 2, 3], [4, 1, 2, 4], [4, 1, 2, 5], [4, 1, 3, 1], [4, 1, 3, 2], [4, 1, 3, 3], [4, 1, 3, 4], [4, 1, 3, 5], [4, 1, 4, 1], [4, 1, 4, 2], [4, 1, 4, 3], [4, 1, 4, 4], [4, 1, 4, 5], [4, 1, 5, 1], [4, 1, 5, 2], [4, 1, 5, 3], [4, 1, 5, 4], [4, 1, 5, 5], [4, 2, 1, 1], [4, 2, 1, 2], [4, 2, 1, 3], [4, 2, 1, 4], [4, 2, 1, 5], [4, 2, 2, 1], [4, 2, 2, 2], [4, 2, 2, 3], [4, 2, 2, 4], [4, 2, 2, 5], [4, 2, 3, 1], [4, 2, 3, 2], [4, 2, 3, 3], [4, 2, 3, 4], [4, 2, 3, 5], [4, 2, 4, 1], [4, 2, 4, 2], [4, 2, 4, 3], [4, 2, 4, 4], [4, 2, 4, 5], [4, 2, 5, 1], [4, 2, 5, 2], [4, 2, 5, 3], [4, 2, 5, 4], [4, 2, 5, 5], [4, 3, 1, 1], [4, 3, 1, 2], [4, 3, 1, 3], [4, 3, 1, 4], [4, 3, 1, 5], [4, 3, 2, 1], [4, 3, 2, 2], [4, 3, 2, 3], [4, 3, 2, 4], [4, 3, 2, 5], [4, 3, 3, 1], [4, 3, 3, 2], [4, 3, 3, 3], [4, 3, 3, 4], [4, 3, 3, 5], [4, 3, 4, 1], [4, 3, 4, 2], [4, 3, 4, 3], [4, 3, 4, 4], [4, 3, 4, 5], [4, 3, 5, 1], [4, 3, 5, 2], [4, 3, 5, 3], [4, 3, 5, 4], [4, 3, 5, 5], [4, 4, 1, 1], [4, 4, 1, 2], [4, 4, 1, 3], [4, 4, 1, 4], [4, 4, 1, 5], [4, 4, 2, 1], [4, 4, 2, 2], [4, 4, 2, 3], [4, 4, 2, 4], [4, 4, 2, 5], [4, 4, 3, 1], [4, 4, 3, 2], [4, 4, 3, 3], [4, 4, 3, 4], [4, 4, 3, 5], [4, 4, 4, 1], [4, 4, 4, 2], [4, 4, 4, 3], [4, 4, 4, 4], [4, 4, 4, 5], [4, 4, 5, 1], [4, 4, 5, 2], [4, 4, 5, 3], [4, 4, 5, 4], [4, 4, 5, 5], [4, 5, 1, 1], [4, 5, 1, 2], [4, 5, 1, 3], [4, 5, 1, 4], [4, 5, 1, 5], [4, 5, 2, 1], [4, 5, 2, 2], [4, 5, 2, 3], [4, 5, 2, 4], [4, 5, 2, 5], [4, 5, 3, 1], [4, 5, 3, 2], [4, 5, 3, 3], [4, 5, 3, 4], [4, 5, 3, 5], [4, 5, 4, 1], [4, 5, 4, 2], [4, 5, 4, 3], [4, 5, 4, 4], [4, 5, 4, 5], [4, 5, 5, 1], [4, 5, 5, 2], [4, 5, 5, 3], [4, 5, 5, 4], [4, 5, 5, 5], [5, 1, 1, 1], [5, 1, 1, 2], [5, 1, 1, 3], [5, 1, 1, 4], [5, 1, 1, 5], [5, 1, 2, 1], [5, 1, 2, 2], [5, 1, 2, 3], [5, 1, 2, 4], [5, 1, 2, 5], [5, 1, 3, 1], [5, 1, 3, 2], [5, 1, 3, 3], [5, 1, 3, 4], [5, 1, 3, 5], [5, 1, 4, 1], [5, 1, 4, 2], [5, 1, 4, 3], [5, 1, 4, 4], [5, 1, 4, 5], [5, 1, 5, 1], [5, 1, 5, 2], [5, 1, 5, 3], [5, 1, 5, 4], [5, 1, 5, 5], [5, 2, 1, 1], [5, 2, 1, 2], [5, 2, 1, 3], [5, 2, 1, 4], [5, 2, 1, 5], [5, 2, 2, 1], [5, 2, 2, 2], [5, 2, 2, 3], [5, 2, 2, 4], [5, 2, 2, 5], [5, 2, 3, 1], [5, 2, 3, 2], [5, 2, 3, 3], [5, 2, 3, 4], [5, 2, 3, 5], [5, 2, 4, 1], [5, 2, 4, 2], [5, 2, 4, 3], [5, 2, 4, 4], [5, 2, 4, 5], [5, 2, 5, 1], [5, 2, 5, 2], [5, 2, 5, 3], [5, 2, 5, 4], [5, 2, 5, 5], [5, 3, 1, 1], [5, 3, 1, 2], [5, 3, 1, 3], [5, 3, 1, 4], [5, 3, 1, 5], [5, 3, 2, 1], [5, 3, 2, 2], [5, 3, 2, 3], [5, 3, 2, 4], [5, 3, 2, 5], [5, 3, 3, 1], [5, 3, 3, 2], [5, 3, 3, 3], [5, 3, 3, 4], [5, 3, 3, 5], [5, 3, 4, 1], [5, 3, 4, 2], [5, 3, 4, 3], [5, 3, 4, 4], [5, 3, 4, 5], [5, 3, 5, 1], [5, 3, 5, 2], [5, 3, 5, 3], [5, 3, 5, 4], [5, 3, 5, 5], [5, 4, 1, 1], [5, 4, 1, 2], [5, 4, 1, 3], [5, 4, 1, 4], [5, 4, 1, 5], [5, 4, 2, 1], [5, 4, 2, 2], [5, 4, 2, 3], [5, 4, 2, 4], [5, 4, 2, 5], [5, 4, 3, 1], [5, 4, 3, 2], [5, 4, 3, 3], [5, 4, 3, 4], [5, 4, 3, 5], [5, 4, 4, 1], [5, 4, 4, 2], [5, 4, 4, 3], [5, 4, 4, 4], [5, 4, 4, 5], [5, 4, 5, 1], [5, 4, 5, 2], [5, 4, 5, 3], [5, 4, 5, 4], [5, 4, 5, 5], [5, 5, 1, 1], [5, 5, 1, 2], [5, 5, 1, 3], [5, 5, 1, 4], [5, 5, 1, 5], [5, 5, 2, 1], [5, 5, 2, 2], [5, 5, 2, 3], [5, 5, 2, 4], [5, 5, 2, 5], [5, 5, 3, 1], [5, 5, 3, 2], [5, 5, 3, 3], [5, 5, 3, 4], [5, 5, 3, 5], [5, 5, 4, 1], [5, 5, 4, 2], [5, 5, 4, 3], [5, 5, 4, 4], [5, 5, 4, 5], [5, 5, 5, 1], [5, 5, 5, 2], [5, 5, 5, 3], [5, 5, 5, 4], [5, 5, 5, 5]]
EDIT-2 : I have fixed some code which previously was returning a nested list, now the list returned is the one with the pairs and is not nested within another list.
EDIT-3-: Fixed my spelling mistakes.
One could also use the function below, to make an explicit list of all states or actions in the observation or action space respectively.
def get_space_list(space):
"""
Converts gym `space`, constructed from `types`, to list `space_list`
"""
# -------------------------------- #
types = [
gym.spaces.multi_binary.MultiBinary,
gym.spaces.discrete.Discrete,
gym.spaces.multi_discrete.MultiDiscrete,
gym.spaces.dict.Dict,
gym.spaces.tuple.Tuple,
]
if type(space) not in types:
raise ValueError(f'input space {space} is not constructed from spaces of types:' + '\n' + str(types))
# -------------------------------- #
if type(space) is gym.spaces.multi_binary.MultiBinary:
return [
np.reshape(np.array(element), space.n)
for element in itertools.product(
*[range(2)] * np.prod(space.n)
)
]
if type(space) is gym.spaces.discrete.Discrete:
return list(range(space.n))
if type(space) is gym.spaces.multi_discrete.MultiDiscrete:
return [
np.array(element) for element in itertools.product(
*[range(n) for n in space.nvec]
)
]
if type(space) is gym.spaces.dict.Dict:
keys = space.spaces.keys()
values_list = itertools.product(
*[get_space_list(sub_space) for sub_space in space.spaces.values()]
)
return [
{key: value for key, value in zip(keys, values)}
for values in values_list
]
return space_list
if type(space) is gym.spaces.tuple.Tuple:
return [
list(element) for element in itertools.product(
*[get_space_list(sub_space) for sub_space in space.spaces]
)
]
# -------------------------------- #

Implementing a nested or multidimensional python list extended slicing

I want to implement a multidimentional list slicing. I call it part like similar built-in function of Mathematica's Part.
What I got so far is below definition.
class slicee:
def __getitem__(self, item):
return item
def part(x,sliceList):
if len(sliceList)==1:
return x[sliceList[0]]
else:
if type(sliceList[0])==slice:
tmp=x[sliceList[0]]
else:
tmp=[x[sliceList[0]]]
return [part(i,sliceList[1:]) for i in tmp]
Now we use this part. Define a nested list(just for convinience, I use all numbers, which I know numpy can slice it perfectly. But it just serves an example.)
l=[[[8, 9, 5, 5], [2, 0, 3, 4], [1, 1, 6, 6], [3, 9, 9, 3]],
[[3, 4, 0, 2], [3, 1, 0, 2], [8, 2, 9, 5], [3, 5, 6, 8]],
[[3, 5, 7, 2], [7, 2, 3, 9], [2, 1, 5, 2], [7, 6, 2, 2]],
[[3, 0, 8, 3], [3, 7, 8, 1], [9, 4, 7, 2], [2, 0, 5, 7]]]
and
part(l,slicee()[:,:,0])
gives
[[8, 2, 1, 3], [3, 3, 8, 3], [3, 7, 2, 7], [3, 3, 9, 2]]
This is quite good except that I don't like the interface which have to explicitly write slicee()
Is it possible to make the interface of part to be part(l,[:,:,0]) or even better part(l,:,:,0)? Or is there already some package deal with this general slicing?
Enlightened by wwii, I made below part class which fix some bugs in both wwii's answer and my post
class part(list):
def __getitem__(self, item):
b=list(self)
def part_internal(x,slice_spec):
if type(slice_spec)==tuple:
if len(slice_spec)>1:
tmp=x[slice_spec[0]]
if type(slice_spec[0])==slice:
return [part_internal(i,slice_spec[1:]) for i in tmp]
else:
return part_internal(tmp,slice_spec[1:])
else:
return x[slice_spec[0]]
else:
return x[slice_spec]
return part_internal(b,item)
Define
l=[[[8, 9, 5, 5], [2, 0, 3, 4], [1, 1, 6, 6], [3, 9, 9, 3]],
[[3, 4, 0, 2], [3, 1, 0, 2], [8, 2, 9, 5], [3, 5, 6, 8]],
[[3, 5, 7, 2], [7, 2, 3, 9], [2, 1, 5, 2], [7, 6, 2, 2]],
[[3, 0, 8, 3], [3, 7, 8, 1], [9, 4, 7, 2], [2, 0, 5, 7]]]
Now we have
print(part(l)[0])
print(part(l)[0,0])
print(part(l)[0,0,0])
print(part(l)[:,0])
print(part(l)[:,:,0])
print(part(l)[:,0:2,0:2])
gives
[[8, 9, 5, 5], [2, 0, 3, 4], [1, 1, 6, 6], [3, 9, 9, 3]]
[8, 9, 5, 5]
8
[[8, 9, 5, 5], [3, 4, 0, 2], [3, 5, 7, 2], [3, 0, 8, 3]]
[[8, 2, 1, 3], [3, 3, 8, 3], [3, 7, 2, 7], [3, 3, 9, 2]]
[[[8, 9], [2, 0]], [[3, 4], [3, 1]], [[3, 5], [7, 2]], [[3, 0], [3, 7]]]
This is the closest I could get. Subclass list and override __getitem__.
class Foo(list):
def __getitem__(self, item):
b = list(self)
for thing in item:
b = b[thing]
return b
a = [[[8, 9, 5, 5], [2, 0, 3, 4], [1, 1, 6, 6], [3, 9, 9, 3]],
[[3, 4, 0, 2], [3, 1, 0, 2], [8, 2, 9, 5], [3, 5, 6, 8]],
[[3, 5, 7, 2], [7, 2, 3, 9], [2, 1, 5, 2], [7, 6, 2, 2]],
[[3, 0, 8, 3], [3, 7, 8, 1], [9, 4, 7, 2], [2, 0, 5, 7]]]
>>> a = Foo(a)
>>> a[:,:,1]
[[3, 4, 0, 2], [3, 1, 0, 2], [8, 2, 9, 5], [3, 5, 6, 8]]
>>> a[:,1,1]
[3, 1, 0, 2]
>>> a[1,1,1]
1
>>>
Caveat: Did not assess unintended consequences. Here are a couple...
>>> a[1,]
[[3, 4, 0, 2], [3, 1, 0, 2], [8, 2, 9, 5], [3, 5, 6, 8]]
>>> a[1]
Traceback (most recent call last):
File "<pyshell#458>", line 1, in <module>
a[1]
File "C:\pyProjects\tmp.py", line 34, in __getitem__
for thing in item:
TypeError: 'int' object is not iterable
>>> a[1,1,1,1]
Traceback (most recent call last):
File "<pyshell#457>", line 1, in <module>
a[1,1,1,1]
File "C:\pyProjects\tmp.py", line 35, in __getitem__
b = b[thing]
TypeError: 'int' object is not subscriptable
In order to implement as a function with two arguments - part(thelist,theslice). You would need to parse theslice argument and expand it to a tuple of slice objects.

List with non-repeating sublists from given list

How to create a list with n-size non-repeating sublists from given list?
I think the example will explain a lot.
given_list = [1, 2, 3, 4, 5]
n = 3
desired_list = [[1,2,3], [1,2,4], [1,2,5], [1,3,4], [1,3,5], [1,4,5], [2,3,4], [2,3,5], [2,4,5], [3,4,5]]
EDIT:
I forgot to add some important combinations
Not sure if you want combinations or permutations, so here are both:
Permutations
You can use permutations from itertools to find all permutations of a given list:
from itertools import permutations
given_list = [1, 2, 3, 4, 5]
n = 3
print([list(i) for i in permutations(given_list, n)])
Output:
[[1, 2, 3], [1, 2, 4], [1, 2, 5], [1, 3, 2], [1, 3, 4], [1, 3, 5], [1, 4, 2], [1
, 4, 3], [1, 4, 5], [1, 5, 2], [1, 5, 3], [1, 5, 4], [2, 1, 3], [2, 1, 4], [2, 1
, 5], [2, 3, 1], [2, 3, 4], [2, 3, 5], [2, 4, 1], [2, 4, 3], [2, 4, 5], [2, 5, 1
], [2, 5, 3], [2, 5, 4], [3, 1, 2], [3, 1, 4], [3, 1, 5], [3, 2, 1], [3, 2, 4],
[3, 2, 5], [3, 4, 1], [3, 4, 2], [3, 4, 5], [3, 5, 1], [3, 5, 2], [3, 5, 4], [4,
1, 2], [4, 1, 3], [4, 1, 5], [4, 2, 1], [4, 2, 3], [4, 2, 5], [4, 3, 1], [4, 3,
2], [4, 3, 5], [4, 5, 1], [4, 5, 2], [4, 5, 3], [5, 1, 2], [5, 1, 3], [5, 1, 4]
, [5, 2, 1], [5, 2, 3], [5, 2, 4], [5, 3, 1], [5, 3, 2], [5, 3, 4], [5, 4, 1], [
5, 4, 2], [5, 4, 3]]
Combinations
And you can use combinations from itertools to find all the combinations of a given list:
from itertools import combinations
given_list = [1, 2, 3, 4, 5]
n = 3
print([list(i) for i in combinations(given_list, n)])
Output:
[[1, 2, 3], [1, 2, 4], [1, 2, 5], [1, 3, 4], [1, 3, 5], [1, 4, 5], [2, 3, 4], [2
, 3, 5], [2, 4, 5], [3, 4, 5]]
A fast implementation of permutations:
sub perm {
my ($init,$k) = #_;
my $n=length($init); my $dn=$n;
my $out=""; my $m=$k;
for (my $i=0;$i<$n;$i++) {
my $ind=$m % $dn;
$out.=substr($init,$ind,1);
$m=$m / $dn;
$dn--;
substr($init,$ind,1,substr($init,$dn,1));
}
return $out
}
k = 0 .. length(init)-1; each k giving an unique permutation, seemly randomly.
to calculate the factorial length(init)!
sub fac {
my ($f) = #_;
my $fac=1; while ($f>1) { $fac*=$f; $f-- } return $fac
}

How to generate all possible k size vectors in a matrix (diagonals included)?

Given this matrix:
x = [[1,2,3,4,5], [1,2,3,4,5], [1,2,3,4,5], [1,2,3,4,5], [1,2,3,4,5], [1,2,3,4,5]]
What is an efficient way to return all the possible 4 by 1 vectors and 1 by 4 matrix in this matrix. As well as any 4 diagonal spaces joined in a line.
For example:
[1,1,1,1] would appear 3 times
Diagonals also need to be addressed so [1,2,3,4] would be included as a row but also a diagonal.
Splitting the problem into two steps:
Step 1 - get all horizontal, vertical and diagonal lines
Diagonals are tackled using the fact either i+j, or respectively i-j, is constant for the indexes i, j
x = [[1,2,3,4,5], [1,2,3,4,5], [1,2,3,4,5], [1,2,3,4,5], [1,2,3,4,5], [1,2,3,4,5]]
pprint.pprint(x)
# [[1, 2, 3, 4, 5],
# [1, 2, 3, 4, 5],
# [1, 2, 3, 4, 5],
# [1, 2, 3, 4, 5],
# [1, 2, 3, 4, 5],
# [1, 2, 3, 4, 5]]
all_lines = (
# Horizontal
[x[i] for i in range(len(x))] +
# Vertical
[[x[i][j] for i in range(len(x))] for j in range(len(x[0]))] +
# Diagonal k = i - j
[[x[k+j][j] for j in range(len(x[0])) if 0 <= k+j < len(x)] for k in range(-len(x[0])+1, len(x))] +
# Diagonal k = i + j
[[x[k-j][j] for j in range(len(x[0])) if 0 <= k-j < len(x)] for k in range(len(x[0])+len(x)-1)]
)
>>> pprint.pprint(all_lines)
[[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 1, 1, 1, 1, 1],
[2, 2, 2, 2, 2, 2],
[3, 3, 3, 3, 3, 3],
[4, 4, 4, 4, 4, 4],
[5, 5, 5, 5, 5, 5],
[5],
[4, 5],
[3, 4, 5],
[2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4],
[1, 2, 3],
[1, 2],
[1],
[1],
[1, 2],
[1, 2, 3],
[1, 2, 3, 4],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[2, 3, 4, 5],
[3, 4, 5],
[4, 5],
[5]]
Step 2 - for each line select each 4-length slice
ans = [a[i:i+4] for i in range(len(a)-4+1) for a in all_lines if len(a[i:i+4]) == 4]
>>> ans = [a[i:i+4] for i in range(len(a)-4+1) for a in all_lines if len(a[i:i+4]) == 4]
>>> pprint.pprint(ans)
[[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3],
[4, 4, 4, 4],
[5, 5, 5, 5],
[2, 3, 4, 5],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[2, 3, 4, 5],
[2, 3, 4, 5],
[2, 3, 4, 5],
[2, 3, 4, 5],
[2, 3, 4, 5],
[2, 3, 4, 5],
[2, 3, 4, 5],
[1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3],
[4, 4, 4, 4],
[5, 5, 5, 5],
[2, 3, 4, 5],
[2, 3, 4, 5],
[2, 3, 4, 5],
[2, 3, 4, 5],
[1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3],
[4, 4, 4, 4],
[5, 5, 5, 5]]
Maybe not be the most efficient but it's at least a way of doing it.
There will likely be a way of using itertools combinations to simplify this dramatically.

Removing Element from Lists of List. PYTHON

for i in file:
file = [i.strip() for i in file]
return [file[i:i+1] for i in range(0, len(file),1)]
OUTPUT:
[['1,3,4,5,2'], ['4,2,5,3,1'], ['1,3,2,5,4'], ['1,2,4,3,5'], ['1,3,4,5,2'], ['2,1,3,5,4'], ['1,3,4,5,2'], ['3,5,2,4,1'], ['1,4,5,2,3'], ['5,1,4,3,2'], ['3,2,5,4,1'], ['3,1,2,5,4'], ['2,5,1,4,3'], ['3,2,1,4,5'], ['4,5,3,1,2'], ['1,5,4,3,2'], ['1,5,3,4,2'], ['2,1,4,3,5'], ['4,1,2,5,3']]
This is my List with sub-lists.
How can I take off the ' '? So ['1,3,4,5,2'] -> [1,3,4,5,2]
Thanks! (:
You can try this:
s = [['1,3,4,5,2'], ['4,2,5,3,1'], ['1,3,2,5,4'], ['1,2,4,3,5'], ['1,3,4,5,2'], ['2,1,3,5,4'], ['1,3,4,5,2'], ['3,5,2,4,1'], ['1,4,5,2,3'], ['5,1,4,3,2'], ['3,2,5,4,1'], ['3,1,2,5,4'], ['2,5,1,4,3'], ['3,2,1,4,5'], ['4,5,3,1,2'], ['1,5,4,3,2'], ['1,5,3,4,2'], ['2,1,4,3,5'], ['4,1,2,5,3']]
final_data = [map(int, i[0].split(",")) for i in s]
Output:
[[1, 3, 4, 5, 2], [4, 2, 5, 3, 1], [1, 3, 2, 5, 4], [1, 2, 4, 3, 5], [1, 3, 4, 5, 2], [2, 1, 3, 5, 4], [1, 3, 4, 5, 2], [3, 5, 2, 4, 1], [1, 4, 5, 2, 3], [5, 1, 4, 3, 2], [3, 2, 5, 4, 1], [3, 1, 2, 5, 4], [2, 5, 1, 4, 3], [3, 2, 1, 4, 5], [4, 5, 3, 1, 2], [1, 5, 4, 3, 2], [1, 5, 3, 4, 2], [2, 1, 4, 3, 5], [4, 1, 2, 5, 3]]
try this:
import ast
l = []
s = [['1,3,4,5,2'], ['4,2,5,3,1'], ['1,3,2,5,4'], ['1,2,4,3,5'], ['1,3,4,5,2'], ['2,1,3,5,4'], ['1,3,4,5,2'], ['3,5,2,4,1'], ['1,4,5,2,3'], ['5,1,4,3,2'], ['3,2,5,4,1'], ['3,1,2,5,4'], ['2,5,1,4,3'], ['3,2,1,4,5'], ['4,5,3,1,2'], ['1,5,4,3,2'], ['1,5,3,4,2'], ['2,1,4,3,5'], ['4,1,2,5,3']]
for li in s:
l.append(list(ast.literal_eval(li[0])))
note: ast is a built-in (standard) module if you don't know it, it cames with python installation
One line solution :
list_1=[['1,3,4,5,2'], ['4,2,5,3,1'], ['1,3,2,5,4'], ['1,2,4,3,5'], ['1,3,4,5,2'], ['2,1,3,5,4'], ['1,3,4,5,2'], ['3,5,2,4,1'], ['1,4,5,2,3'], ['5,1,4,3,2'], ['3,2,5,4,1'], ['3,1,2,5,4'], ['2,5,1,4,3'], ['3,2,1,4,5'], ['4,5,3,1,2'], ['1,5,4,3,2'], ['1,5,3,4,2'], ['2,1,4,3,5'], ['4,1,2,5,3']]
print([[int(item_3) for item_3 in item_1 if item_3.isdigit()] for item in list_1 for item_1 in item])
output:
[[1, 3, 4, 5, 2], [4, 2, 5, 3, 1], [1, 3, 2, 5, 4], [1, 2, 4, 3, 5], [1, 3, 4, 5, 2], [2, 1, 3, 5, 4], [1, 3, 4, 5, 2], [3, 5, 2, 4, 1], [1, 4, 5, 2, 3], [5, 1, 4, 3, 2], [3, 2, 5, 4, 1], [3, 1, 2, 5, 4], [2, 5, 1, 4, 3], [3, 2, 1, 4, 5], [4, 5, 3, 1, 2], [1, 5, 4, 3, 2], [1, 5, 3, 4, 2], [2, 1, 4, 3, 5], [4, 1, 2, 5, 3]]
in detailed :
for item in list_1:
for item_1 in item:
new=[]
for item_3 in item_1:
if item_3.isdigit():
new.append(int(item_3))
print(new)

Categories