What are some good ways to define a tuple consisting of integers where the number of occurrences of each item is known ?
For example,
I want to define a tuple with 3 2's, 2 4's and 1, 3, 5 occur once.
For this, I can always go the manual way :
foo = (1, 2, 2, 2, 3, 4, 4, 5)
However, this becomes a bit messy when the number of items in the list is large.
So, I want to know what are some ways to automate the task of generating the desired number of duplicates of each item.
You can do it like this:
>>> (1,) * 1 + (2,) * 3 + (4,) * 2 + (5,) * 1
(1, 2, 2, 2, 4, 4, 5)
One way is to use sequence multiplication. Here's a simple version that makes no attempt to avoid creating unnecessary intermediate objects:
accumulator = ()
for (val, count) in some_data_structure:
accumulator += (val,) * count
That can be improved, the main point is to demonstrate that (1,) * 5 gives you (1, 1, 1, 1, 1). Note that this copies the object reference - that's fine for integers, but can cause confusion if you're trying to multiply a sequence of mutable objects.
If you have a tuple of tuples denoting the value and frequency, you can do the following:
tuples = ((1,1), (2,3), (3,1), (4,2), (5,1))
tuple(i for i, n in tuples for _ in range(n)) # Use xrange in Python 2.X
# (1, 2, 2, 2, 3, 4, 4, 5)
Or, if you know that the values are always going to be 1, 2, 3, ..., n, you can use enumerate with a tuple of the frequencies.
freqs = (1, 3, 1, 2, 1)
tuple(i for i, n in enumerate(freqs, 1) for _ in range(n))
# (1, 2, 2, 2, 3, 4, 4, 5)
If you're curious about the use of the double comprehension in the generator expression, you may want to check out this question.
If your tuple has not many number, you can do it in the simplest way.
(1,)+(2,)*3+(3,)+(4,)*2+(5,)
Otherwise, just turn it into a function.
def myTuple(*val):
return sum(((i,) * n for i, n in val), ())
myTuple((1,1),(2,3),(3,1),(4,2),(5,1))
>>>(1, 2, 2, 2, 3, 4, 4, 5)
you can also call it with:
val = ((1,1),(2,3),(3,1),(4,2),(5,1))
myTuple(*val)
>>>(1, 2, 2, 2, 3, 4, 4, 5)
Something like this could work:
>>> result = tuple()
>>> for item, repeat in ((1, 1), (2, 3), (3, 1), (4, 2), (5, 1)):
... result = result + (item,) * repeat
>>> result
(1, 2, 2, 2, 3, 4, 4, 5)
So you want the inverse function of collections.Counter. Here is how you could do it,
# make a dict of counts (list of tuples is better)
counts = {1: 1, 2: 3, 4: 2, 3:1, 5: 1}
t = tuple(k for k,v in sorted(counts.items()) for _ in range(v))
(1, 2, 2, 2, 3, 4, 4, 5)
# for k,v in list_of_tuples, for a list of tuples
You can define the following function
def a_tuple(*data):
l = []
for i, cnt in data: l.extend([i]*cnt)
return tuple(l)
and use it like this
print(a_tuple((1,1), (2,3), (3,1), (4,2), (5,1)))
to produce the following output
(1, 2, 2, 2, 3, 4, 4, 5)
Have a look to the .extend() method of list if you don't understand how the function works.
Related
I'm trying to make a general way to generate all the combinations of multiple ranges or lists, for example,
[range(0, 2), range(2, 5), range(4, 6), range(2, 3)],
which should return a 2x3x2x1 = 12 element list.
[[0, 2, 4, 2],
[0, 2, 5, 2],
[0, 3, 4, 2],
[0, 3, 5, 2],
[0, 4, 4, 2],
[0, 4, 5, 2],
[1, 2, 4, 2],
[1, 2, 5, 2],
[1, 3, 4, 2],
[1, 3, 5, 2],
[1, 4, 4, 2],
[1, 4, 5, 2]]
So far, everything is fine here. When I hardcode it, by doing
x = [ ( [a,b] for a in rgs[0] for b in rgs[1] ) ]
x.append( ( a + [b] for a in x[-1] for b in rgs[2]) )
x.append( ( a + [b] for a in x[-1] for b in rgs[3]) )
I get the good result. However, when I attempt to generalize it, by doing
x = [ ( [a,b] for a in rgs[0] for b in rgs[1] ) ]
for i in range(1,len(rgs)-1):
x.append( ( a + [b] for a in x[-1] for b in rgs[i+1]) )
I obtain a 6-element list:
[[0, 2, 2, 2],
[0, 3, 2, 2],
[0, 4, 2, 2],
[1, 2, 2, 2],
[1, 3, 2, 2],
[1, 4, 2, 2]]
Also, what I notice is that all the ranges generated after the first two use the range in rgs[-1] instead of the correct ones. I struggle to understand why this happens, as I beleive that those two code example are identical, except the latter is the more general form for arbitrary large number of ranges.
You can use itertools.product to output a list of tuples
Input:
import itertools
a= [range(0, 2), range(2, 5), range(4, 6), range(2, 3)]
list(itertools.product(*a))
Output:
[(0, 2, 4, 2),
(0, 2, 5, 2),
(0, 3, 4, 2),
(0, 3, 5, 2),
(0, 4, 4, 2),
(0, 4, 5, 2),
(1, 2, 4, 2),
(1, 2, 5, 2),
(1, 3, 4, 2),
(1, 3, 5, 2),
(1, 4, 4, 2),
(1, 4, 5, 2)]
I did not get the same result when running your first code. I had to change it up a bit:
x = [ ( [a,b] for a in rgs[0] for b in rgs[1] ) ]
x.append( ( a + [b] for a in x[-1] for b in rgs[2]) )
x = list( a + [b] for a in x[-1] for b in rgs[3])
Most people that don't know about itertools would have done it this way:
x=[]
for i0 in rgs[0]:
for i1 in rgs[1]:
for i2 in rgs[2]:
for i3 in rgs[3]:
x.append([i0,i1,i2,i3])
Or using a list comprehension (DON'T DO THIS, it is VERY messy looking):
[[i0,i1,i2,i3] for i3 in rgs[3] for i2 in rgs[2] for i1 in rgs[1] for i0 in rgs[0]]
Your issue has to do with creating generator expressions in a loop. Generator expressions are implemented as functions, and like functions, they can have "free" variables that they look up in the containing namespaces. Your generator expressions are accessing the i from outside their definition, and because of this, they end up seeing a different i value you expect.
Here's an example that might be easier to understand:
def gen()
print(i)
yield 10
x = []
for i in range(3):
x.append(gen()) # add several generators while `i` has several different values
for g in x:
list(g) # consume the generators, so they can print `i`
Here, rather than using the i value for something useful, I've written a generator function that just prints it out. If you run this code, you'll see that all the generators print out 2, since that's the value of i when they finally run (after the first loop ended).
Your situation is a little more subtle, as you're consuming the previous generator as you create the next one, but the general idea is the same. The generator expression loop that you expect to be over rgs[2] is actually over rgs[3] because it's actually being looked up with rgs[i+1] and i increased between the time the generator expression was declared and when it was consumed.
I need to convert a structure like this:
(1, 2, 3, 4, 5, 6)
To a dictionnary like this:
{1: 2, 3: 4, 5: 6}
How would you proceed ?
Pair up the elements 2 by two and pass the result to dict():
result = dict(zip(*[iter(values)] * 2))
By using iter() here you avoid creating two in-memory list objects the way [::2] and [1::2] slicing would. See Iterating over every two elements in a list as to why this works.
Demo:
>>> values = (1, 2, 3, 4, 5, 6)
>>> dict(zip(*[iter(values)] * 2))
{1: 2, 3: 4, 5: 6}
The idea is to zip together two slices of the tuple with step 2 - first one starting with the 0th element and the second - with the 1st element, and then pass the result to the dict() constructor:
>>> t = (1, 2, 3, 4, 5, 6)
>>> dict(zip(t[::2], t[1::2]))
{1: 2, 3: 4, 5: 6}
Just to expand that, here are the intermediate values:
>>> t[::2]
(1, 3, 5)
>>> t[1::2]
(2, 4, 6)
Now the zip() would aggregate the elements together, group by position:
>>> zip(t[::2], t[1::2])
[(1, 2), (3, 4), (5, 6)]
Then, the dict() would make a dictionary out of the list of pairs using first elements of the items as keys and second elements as values.
Note that the downside of this approach is that there would be two extra lists created in memory as opposed to #Martijn's proposal. Though, this approach is arguably simpler and more readable.
This question already has answers here:
How do I generate all permutations of a list?
(40 answers)
Closed 8 years ago.
I want to write a recursive function p() that takes a list and returns a list of all permutations of the input list.
Ex.
>>>permutations([1, 2,3])
[[1, 2,3],[2, 1, 3],[2, 3, 1],[1, 3, 2],[3, 1, 2],[3, 2, 1]]
I want to recursively call on a sublist l[1:] for all permutations of all elements of the original input list except the first element, l[0], and then generate the permutations of the original list by adding l[0] to those permutations.
So far, I have
def p(list):
if len(list)==1 or 0:
return list
result = []
for i in list[1:]:
result.append(i + list[0])
result += [list]
return result
But I know something is wrong.... help please?
I don't know that is what you want but check it out
from itertools import permutations
l = [1, 2, 3, 4, 5]
new_l = list(permutations(l, len(l)))
it will output something like
[(1, 2, 3, 4, 5),
(1, 2, 3, 5, 4),
(1, 2, 4, 3, 5),
(1, 2, 4, 5, 3),
(1, 2, 5, 3, 4),
...
Hope this helps!
I need to decompress an array and I am not sure where to start.
Here is the input of the function
def main():
# Test case for Decompress function
B = [6, 2, 7, 1, 3, 5, 1, 9, 2, 0]
A = Decompress(B)
print(A)
I want this to come out
A = [2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, 9, 0, 0]
If you can't see the pattern, B[1] is how many times B[2] shows up in A[], and then B[3] is how many times B[4] shows up in A[], and so on.
How do I write a function for this?
Compact version with zip() and itertools.chain.from_iterable:
from itertools import chain
list(chain.from_iterable([v] * c for c, v in zip(*([iter(B)]*2))))
Demo:
>>> B = [6, 2, 7, 1, 3, 5, 1, 9, 2, 0]
>>> from itertools import chain
>>> list(chain.from_iterable([v] * c for c, v in zip(*([iter(B)]*2))))
[2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, 9, 0, 0]
Breaking this down:
zip(*([iter(B)]*2))) pairs counts with values:
>>> zip(*([iter(B)]*2))
[(6, 2), (7, 1), (3, 5), (1, 9), (2, 0)]
It is a fairly standard Python trick to get pairs out of a input iterable.
([v] * c for c, v in zip(*([iter(B)]*2))) is a generator expression that takes the counts and values and produces lists with the value repeated count times:
>>> next([v] * c for c, v in zip(*([iter(B)]*2)))
[2, 2, 2, 2, 2, 2]
chain.from_iterable takes the various lists produced by the generator expression and lets you iterate over them as if they were one long list.
list() turns it all back to a list.
def unencodeRLE(i):
i = list(i) #Copies the list to a new list, so the original one is not changed.
r = []
while i:
count = i.pop(0)
n = i.pop(0)
r+= [n for _ in xrange(count)]
return r
One more one-liner:
def decompress(vl):
return sum([vl[i] * [vl[i+1]] for i in xrange(0, len(vl), 2)], [])
A list comprehension extracts and unpacks pairs (xrange(0, len(vl), 2) iterates through start indices of pairs, vl[i] is a number of repetitions, vl[i+1] is what to repeat).
sum() joins the results together ([] is the initial value the unpacked lists are sequentially added to).
A slightly faster solution (with Python 2.7.3):
A=list(chain.from_iterable( [ B[i]*[B[i+1]] for i in xrange(0,len(B),2) ] ) )
>>> timeit.Timer(
setup='B=[6,2,7,1,3,5,1,9,2,0];from itertools import chain',
stmt='A=list(chain.from_iterable( [ B[i]*[B[i+1]] for i in xrange(0,len(B),2) ] ) )').timeit(100000)
0.22841787338256836
Comparing with:
>>> timeit.Timer(
setup='B=[6,2,7,1,3,5,1,9,2,0];from itertools import chain',
stmt='A=list(chain.from_iterable([v] * c for c, v in zip(*([iter(B)]*2))))').timeit(100000)
0.31104111671447754
I have a list [2,3,4]. How do I find all possible sequence of elements in the list?
So the output should be:
[2,3,4]
[2,4,3]
[3,2,4]
[3,4,2]
[4,2,3]
[4,3,2]
You can do this easily using itertools.permutations():
>>> from itertools import permutations
>>> list(permutations([2, 3, 4]))
[(2, 3, 4), (2, 4, 3), (3, 2, 4), (3, 4, 2), (4, 2, 3), (4, 3, 2)]
And if for some reason you need lists instead of tuples:
>>> map(list, permutations([2, 3, 4]))
[[2, 3, 4], [2, 4, 3], [3, 2, 4], [3, 4, 2], [4, 2, 3], [4, 3, 2]]
You are looking for permutations, something like this should work:
import itertools
itertools.permutations([2,3,4])
a start of a great lottery program except data would be formated as such
ist(permutations([2, 3, 4],[7,2,5],[8,1,4,9]))
the problem is that the first group is used to create numbers in first column only
the secound is for 2 column and 3rd is for 3rd
the output will be a set of 3 numbers just that the permutation is different
Just so you know:
def unique_perms(elems):
"""returns non-duplicate permutations
if duplicate elements exist in `elems`
"""
from itertools import permutations
return list(set(permutations(elems)))
But if you're doing something like this:
print len(unique_perms(elems))
Then try this:
def fac(n):
"""n!"""
if n == 1: return n
return n * fac(n -1)
def unique_perm_count(elems)
n = len(elems)
return fac(2 * n) / fac(n) ** 2