Converting a vector of ranges into combination of sets in Python - python

In Python, I have a list of ranges like that:
A = [range(0,2),range(0,4),range(0,3),range(0,3)]
First I have to convert all of these ranges into sets. I can create an empty set and add the resulting list to it. I would have:
B = [[0, 1], [0, 1, 2, 3], [0, 1, 2], [0, 1, 2]]
But after that, I have to create all the possible combinations of elements between the lists. The set with the lowest values would be [0, 0, 0, 0] and the highest values would be: [1, 3, 2, 2]. It would be a combination of 2x4x3x3 = 72 sets. How can I achieve this result, starting with the list of ranges (A)?

You can use the built-in itertools module to take the cartesian product of all the range objects in A, and skip making B altogether:
import itertools
A = [range(2), range(4), range(3), range(3)]
list(itertools.product(*A))
Output (skipping some items for readability):
[(0, 0, 0, 0),
(0, 0, 0, 1),
(0, 0, 0, 2),
(0, 0, 1, 0),
(0, 0, 1, 1),
.
.
.
(1, 3, 2, 2)]
Verifying the length:
>>> len(list(itertools.product(*A)))
72
Note that itertools.product() yields tuple objects. If for whatever reason you'd prefer these to be lists, you can use a comprehension:
[[*p] for p in itertools.product(*A)]
Another approach, as #don'ttalkjustcode points out, is that you can avoid creating A entirely and skip directly to the cartesian product via the map() function:
list(itertools.product(*map(range, (2, 4, 3, 3))))
However, this assumes that all your ranges start at 0.
You could generalize this mapping technique by using a lambda which will create range objects from a list of tuples:
>>> list(map(lambda t: range(*t), ((6, -3, -1), (0, 3), (5,), (10, 1, -2))))
[range(6, -3, -1), range(0, 3), range(0, 5), range(10, 1, -2)]

to get the Cartesian product do the following :
A = []
for i in range(2):
for j in range(4):
for k in range(3):
for n in range(3):
combo = [i,j,k,n]
A.append(combo)

Related

Generate k-combinations with replacement of n-size set using maximum s-number of elements of n-size set (where s<n)

I know how to get all possible combinations with replacement using itertools, but I want to limit the number of combinations with replacement by using limited number of elements from a larger set.
To give an example, I have a set
[0,1,2]
and I want to get k-combinations with replacement (k=4) but using maximum 2 different elements from a set [0,1,2]
so sets of elements that can appear in each combination are:
[0,1], [1,2], [0,2].
Here, I also want to avoid repetition of combinations, so in this example [0,0,0,0], [1,1,1,1] or [2,2,2,2] should not duplicate.
The output for this example:
[0,0,0,0]
[0,0,0,1]
[0,0,1,1]
[0,1,1,1]
[1,1,1,1]
[1,1,1,2]
[1,1,2,2]
[1,2,2,2]
[2,2,2,2]
[0,0,0,2]
[0,0,2,2]
[0,2,2,2]
I hope I am clear.
You can try the following.
import itertools
s = [0,1,2]
k = 4
limit = 2
result = set()
for c in itertools.combinations(s, limit):
result.update(itertools.combinations_with_replacement(c, k))
Or with a set comprehension:
result = {
r
for c in itertools.combinations(s, 2)
for r in itertools.combinations_with_replacement(c, k)
}
Both result in:
print(*result, sep="\n")
(0, 0, 0, 1)
(0, 1, 1, 1)
(0, 0, 0, 0)
(0, 2, 2, 2)
(2, 2, 2, 2)
(1, 2, 2, 2)
(1, 1, 1, 2)
(1, 1, 2, 2)
(0, 0, 0, 2)
(0, 0, 1, 1)
(1, 1, 1, 1)
(0, 0, 2, 2)

How to cast set in list into list in python?

I want to cast set in list to list like below.
before: [(1, 1, 1), (1, 1, 0), (1, 0, 1)]
after: [[1, 1, 1], [1, 1, 0], [1, 0, 1]]
I need the as simple code as possible.
>>> x = [(1, 1, 1), (1, 1, 0), (1, 0, 1)]
>>> list(map(list, x))
[[1, 1, 1], [1, 1, 0], [1, 0, 1]]
Explanation
map(list, x) takes an iterable x and applies function list to each element of this iterable. Thus the tuple (1, 1, 1) becomes the list [1, 1, 1], (1, 1, 0) becomes [1, 1, 0] and (1, 0, 1) becomes [1, 0, 1].
These lists are then stored in a map object (assuming Python 3.x). A map object is an iterator, which can be converted to a list by calling list on it, as shown above. Often, though, you don't need to make this explicit conversion because iterator allows you to traverse the elements directly:
>>> for elem in map(list, x):
... print(elem)
...
[1, 1, 1]
[1, 1, 0]
[1, 0, 1]
Let's define "before" as a variable called "array". Then we take the for-loop of the "array" while casting each element to a list.
array = [(1,1,1), (1,1,0), (1,0,1)]
casted_array = []
for tuples in array:
casted_array.append(list(tuples))
There are slightly easier ways to do this, but they are harder to understand. Explanation: You define the list [(1,1,1), (1,1,0), (1,0,1)] as a variable and then define a "dummy" variable called "casted_array". You then loop through the items in the "array" variable while saving them to the "tuples" iteration variable. Every time the iteration cycle loops, the sets/tuples are converted into lists and then added on to the "casted_array" variable. The casted set/tuple is now stored in the "casted_array" variable.

Python How to repeat a list's elements in another list content until the length of the second list fulfilled?

How to repeat a list's elements in another list content until the length of the second list fulfilled?
For example:
LA = [0,1,2]
LB = [(0,0),(1,0),(2,0),(3,0),(4,0),(5,0),(6,0)]
the end result should be:
LC = [(0,0,0),(1,0,1),(2,0,2),(3,0,0),(4,0,1),(5,0,2),(6,0,0)]
Hopefully it can be done in one line
You can use itertools.cycle:
from itertools import cycle
LA = [0,1,2]
LB = [(0,0),(1,0),(2,0),(3,0),(4,0),(5,0),(6,0)]
LC = [(i, j, k) for (i, j), k in zip(LB, cycle(LA))]
print LC
# [(0, 0, 0), (1, 0, 1), (2, 0, 2), (3, 0, 0), (4, 0, 1), (5, 0, 2), (6, 0, 0)]
This works because zip generates items until one of the iterables is exhausted...but a cycle object is inexhaustible, so we'll keep padding items from LA until LB runs out.
#use list comprehension and get the element from LA by using the index from LB %3.
[v+(LA[k%3],) for k,v in enumerate(LB)]
Out[718]: [[0, 0, 0], [1, 0, 1], [2, 0, 2], [3, 0, 0], [4, 0, 1], [5, 0, 2], [6, 0, 0]]
Try enumerate() like this along with list comprehension -
[elem + (LA[i % len(LA)],) for i, elem in enumerate(LB)]
Here a more "explicit" version that works with any length of LA.
LA = [0,1,2]
LB = [(0,0),(1,0),(2,0),(3,0),(4,0),(5,0),(6,0)]
i = 0
LC = []
for x,y in LB:
try:
z = LA[i]
except IndexError:
i = 0
z = LA[i]
LC.append((x,y,z))
i += 1
print LC
[(0, 0, 0), (1, 0, 1), (2, 0, 2), (3, 0, 0), (4, 0, 1), (5, 0, 2), (6, 0, 0)]

Python: Generating all n-length arrays combinations of values within a range

Ok. I'm looking for the smartest and more compact way to do this function
def f():
[[a,b,c] for a in range(6) for b in range(6) for c in range(6)]
which should generate all the combinations for the values a,b,c like this:
[0,0,0]
[0,0,1]
[0,0,2]
...
[1,0,0]
[1,0,1]
...
and so on...
But I want this to be flexible, so I can change the range or iterable, and also the length of the generated arrays. Range is an easy thing:
def f(min, max):
[[a,b,c] for a in range(min,max) for b in range(min,max) for c in range(min,max)]
This is ok for 3-length arrays, but I'm thinking now of making 4-length arrays or 7-length arrays and generate all combinations for them in the same range.
It has to exist an easy way, maybe with concatenating arrays or nesting comprehension lists in some way, but my solutions seem to bee too much complex.
Sorry for such a long post.
You can use itertools.product which is just a convenience function for nested iterations. It also has a repeat-argument if you want to repeat the same iterable multiple times:
>>> from itertools import product
>>> amin = 0
>>> amax = 2
>>> list(product(range(amin, amax), repeat=3))
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)]
To get the list of list you could use map:
>>> list(map(list, product(range(amin, amax), repeat=3)))
[[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
However product is an iterator so it's really efficient if you just iterate over it instead of casting it to a list. At least if that's possible in your program. For example:
>>> for prod in product(range(amin, amax), repeat=3):
... print(prod) # one example
(0, 0, 0)
(0, 0, 1)
(0, 1, 0)
(0, 1, 1)
(1, 0, 0)
(1, 0, 1)
(1, 1, 0)
(1, 1, 1)
You can use itertools.product:
from itertools import product
def f(minimum, maximum, n):
return list(product(*[range(minimum, maximum)] * n))
Drop list to return a generator for memory efficiency.
itertools has everything you need. combinations_with_replacement will generate combinations of given length with repeating elements from given iterable. Note that returned value will be iterator.
def f(min, max, num):
return itertools.combinations_with_replacement(range(min, max), num)
A pure python implementation :
k=2 # k-uples
xmin=2
xmax=5
n=xmax-xmin
l1 = [x for x in range(n**k)]
l2 = [[ x//n**(k-j-1)%n for x in l1] for j in range(k)]
l3 = [[ xmin + l2[i][j] for i in range(k)] for j in range(n**k)]
l3 is :
[[2 2]
[2 3]
[2 4]
[3 2]
[3 3]
[3 4]
[4 2]
[4 3]
[4 4]]
What you are looking for is the cartesian product of the ranges. Luckily this already exists in itertools
import itertools
print(list(itertools.product(range(0,5), range(0,5), range(0,5))))

Permutations and indexes, python

I create a list of all permutations of lets say 0,1,2
perm = list(itertools.permutations([0,1,2]))
This is used for accessing indexes in another list in that specific order. Every time a index is accessed it is popped.
When an element is popped, the elements with indexes higher than the popped elements index will shift one position down. This means that if I want to pop from my list by indexes [0,1,2] it will result in an index error, since index 2 will not exist when I reach it. [0,1,2] should therefor be popped in order [0,0,0].
more examples is
[0,2,1] = [0,1,0]
[2,0,1] = [2,0,0]
[1,2,0] = [1,1,0]
right now this is being handled through a series of checks, my question is if anyone knows a smart way to turn the list of lists generated by itertools into the desired list:
[(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
[(0, 0, 0), (0, 1, 0), (1, 0, 0), (1, 1, 0), (2, 0, 0), (2, 1, 0)]
Simply iterate through each tuple, and decrement the indexes of each subsequent index that is greater than that element:
l=[(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
def lower_idxs(lst):
new_row = list(lst)
for i, val in enumerate(new_row):
for j in xrange(i+1, len(new_row)):
if new_row[i] < new_row[j]:
new_row[j] -= 1
return new_row
print [lower_idxs(x) for x in l]
will print out
[[0, 0, 0], [0, 1, 0], [1, 0, 0], [1, 1, 0], [2, 0, 0], [2, 1, 0]]
Here is a fancier one-liner based on Randy C's solution:
print [tuple(y-sum(v<y for v in x[:i]) for i,y in enumerate(x)) for x in l]
Here's a one-liner for it (assuming your list is l):
[v-sum(v>v2 for v2 in l[:k]) for k, v in enumerate(l)]

Categories

Resources