finding the greater value in tuples - python

As i am beginner i need to find out the tuple which has only one value in it. for ex
a = [4, 0, 0, 4, 0, 0]
b = [0, 0, 0, 0, 0, 0]
d = [5, 0, 5, 0, 0, 0]
f = [0, 1, 0, 0, 0, 0]
This is lists value, by zipping it i get [(4, 0, 5, 0), (0, 0, 0, 1), (0, 0, 5, 0), (4, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)] this value.
In this i want to select which as only one value in tuples for ex my output should look like this [(0, 0, 0, 1), (4, 0, 0, 0)].
Please help me on it

Using a list comprehension:
[x for x in zipped if len(x) == x.count(0) + 1]

Related

Python3 - Permutations for 7 digit number that totals to a number

I need to find a solution for the below problem in Python3. I tried itertools.combinations but not clear on how to do it.
Prepare a 7-digit number that sums to 5. Each digit can be between 0-4 only. Also, there can be repetitions. Valid example numbers are -
[ [2,1,1,0,0,1,0], [3,0,1,0,0,1,0], [0,0,0,4,0,0,1], [1,0,0,3,0,1,0], [1,1,1,1,0,1,0], ...... ]
As you can see, numbers may appear more than once in this list.
How can I create a list of all combinations meeting the criteria above?
You can get all that sum to 5 with:
list(p for p in itertools.product(range(5),repeat = 7) if sum(p) == 5)
This yields 455 solutions.
This function will find every combination, with repeated combinations, that sum to N:
from itertools import product
from typing import List, Tuple
def perm_n_digit_total(n_digits, total, choices) -> List[Tuple]:
return list(filter(
lambda x: sum(x) == total,
product(choices, repeat=n_digits)
))
Example:
perm_n_digit_total(3, 1, range(4))
Out[43]: [(0, 0, 1), (0, 1, 0), (1, 0, 0)]
perm_n_digit_total(7, 5, range(4))[::50]
Out[49]:
[(0, 0, 0, 0, 0, 0, 5),
(0, 0, 0, 3, 1, 1, 0),
(0, 0, 2, 0, 3, 0, 0),
(0, 1, 0, 1, 3, 0, 0),
(0, 2, 0, 0, 1, 0, 2),
(0, 4, 1, 0, 0, 0, 0),
(1, 0, 1, 1, 1, 0, 1),
(1, 1, 1, 1, 1, 0, 0),
(2, 0, 1, 0, 0, 2, 0),
(3, 1, 0, 0, 0, 1, 0)]
Here's an itertools'less recursive solution.
def find_solutions(target, numbers, depth, potential_solution=[]):
if depth == 0:
if sum(potential_solution) == target:
print(potential_solution)
return
current_sum = sum(potential_solution)
for n in numbers:
new_sum = current_sum + n
if new_sum > target:
continue
find_solutions(target, numbers, depth - 1, potential_solution + [n])
find_solutions(target=5, numbers=[0,1,2,3,4], depth=7)
Output
[0, 0, 0, 0, 0, 1, 4]
[0, 0, 0, 0, 0, 2, 3]
[0, 0, 0, 0, 0, 3, 2]
[0, 0, 0, 0, 0, 4, 1]
[0, 0, 0, 0, 1, 0, 4]
[0, 0, 0, 0, 1, 1, 3]
...
[3, 1, 1, 0, 0, 0, 0]
[3, 2, 0, 0, 0, 0, 0]
[4, 0, 0, 0, 0, 0, 1]
[4, 0, 0, 0, 0, 1, 0]
[4, 0, 0, 0, 1, 0, 0]
[4, 0, 0, 1, 0, 0, 0]
[4, 0, 1, 0, 0, 0, 0]
[4, 1, 0, 0, 0, 0, 0]
If I got it, you need something like this:
import itertools
value = [0, 1, 2, 3, 4]
p = itertools.product(value, repeat=7)
for j in list(p):
print(j)
As each digit can only take 5 unique values - you would require itertools.combinations_with_replacement -
from itertools import combinations_with_replacement
zero_four = list(range(5))
for c in combinations_with_replacement(zero_four, 7):
if sum(c) == 5:
print(c)
This will give you all possible combinations that sum to 5 but not all the permutations -
Output
(0, 0, 0, 0, 0, 1, 4)
(0, 0, 0, 0, 0, 2, 3)
(0, 0, 0, 0, 1, 1, 3)
(0, 0, 0, 0, 1, 2, 2)
(0, 0, 0, 1, 1, 1, 2)
(0, 0, 1, 1, 1, 1, 1)
To get all permutations - you can use the itertools.permutations but since your output can have repeated elements, you will need to use a set to retain only unique permutations -
for c in combinations_with_replacement(zero_four, 7):
if sum(c) == 5:
print(set(permutations(c)))

How to iterate over the set of arrays with a fixed sum

Consider all arrays of l non-negative integers in the range 0,...,m. I would like to iterate (using a generator) over only those whose sum is exactly s.
For example, take l=7, s=5, m=4, the iteration could look like:
(0, 0, 0, 0, 0, 1, 4)
(0, 0, 0, 0, 0, 2, 3)
(0, 0, 0, 0, 0, 3, 2)
(0, 0, 0, 0, 0, 4, 1)
(0, 0, 0, 0, 1, 0, 4)
(0, 0, 0, 0, 1, 1, 3)
(0, 0, 0, 0, 1, 2, 2)
(0, 0, 0, 0, 1, 3, 1)
(0, 0, 0, 0, 1, 4, 0)
[...]
(3, 2, 0, 0, 0, 0, 0)
(4, 0, 0, 0, 0, 0, 1)
(4, 0, 0, 0, 0, 1, 0)
(4, 0, 0, 0, 1, 0, 0)
(4, 0, 0, 1, 0, 0, 0)
(4, 0, 1, 0, 0, 0, 0)
(4, 1, 0, 0, 0, 0, 0)
I don't mind which order the iteration happens in but I would like it to be efficient.
A really dumb way to reproduce the above that is far too slow for larger values of the variables is:
import itertools
s = 5
l = 7
m = 5
for arr in itertools.product(range(m), repeat=l):
if sum(arr) == s:
print(arr)
Think of the problem this way, you want to put s balls in l buckets with no more than m balls in any one bucket.
Since I know how to add one ball at a time, my instinct is to solve this using recursion. The base case is putting 0 balls instead of s and to go from one step to the next, adding 1 ball to each of the buckets that currently have less than m balls in them.
To make sure it's actually possible to complete the recursion, we first check there is enough places to put the balls.
# this helper function tells us the last non zero index in an array
def last_non_zero(arr):
indx = -1
while arr[indx] == 0 and indx > -len(arr):
indx -= 1
return len(arr) + indx
def balls_in_buckets(num_balls, num_buckets, max_balls):
assert num_buckets * max_balls >= num_balls, f"You can't put {num_balls} balls in {num_buckets} buckets without more than {max_balls} in a bucket."
if num_balls == 0:
yield ([0]*num_buckets).copy()
else:
for array in balls_in_buckets(num_balls - 1, num_buckets, max_balls):
for bucket_number in range(last_non_zero(array), num_buckets):
if array[bucket_number] < max_balls:
array_copy = array.copy()
array_copy[bucket_number] += 1
yield array_copy
Edit: Added code to remove duplicates
Edit: Performance improvement, takes about 2 seconds to generate the whole sequence for l=14, s=10, m=8. There are 1,143,870 items in the sequence.
What you are looking for are called "partitions". Unfortunately, there's some ambiguity as to whether "partitions" refers to splitting a set into partitions (e.g. [a,b,c] into [[a,b],[c]]), just the numbers characterizing size of each split (e.g. [2,1]), or the count of how many different splitting there are. The most promising search terms I found were "partition a number into k parts python", yielding Python Integer Partitioning with given k partitions and "python partition of indistinguishable items" yielding Partition N items into K bins in Python lazily . Those answers focus on partitions with at least one element, while you allow partitions to include zero elements. In addition, you seem to care about the order within a partition. For instance, you list (0, 0, 0, 0, 0, 1, 4), (0, 0, 0, 0, 0, 4, 1), and (0, 0, 0, 0, 1, 0, 4) as distinct partitions, while traditionally those would be considered equivalent.
I think the best way is to iterate through the buckets, and for each one iterate through the possible values. I changed the parameter names; l, s, and m and not very informative names, and "sum" and "max" are built-in functions. My current version, which may need more debugging:
def get_partitions(length, total, upper_bound):
if length == 1:
if total > upper_bound:
return []
return [[total]]
if total == 0:
return [[0]*length]
return [ [n]+sub_partition for
n in range(min(total, upper_bound)+1) for
sub_partition in get_partitions(
length-1, total-n, upper_bound)]
Side note: I initially read "iterate over the arrays" as meaning "go through the elements of the array". I think that the proper terminology is "iterate over the set of such arrays". When you say "iterate over x", x is being treated as the iterable, not the elements of the iterable.
By modyfing this answer, taking into account max_value:
def sums(length, total_sum, max_value):
if length == 1:
yield (total_sum,)
else:
for value in range(max(0, total_sum - (length - 1) * max_value),
min(max_value, total_sum) + 1):
for permutation in sums(length - 1, total_sum - value, max_value):
yield (value,) + permutation
L = list(sums(7,5, 4))
print('total permutations:',len(L))
# First and last 10 of list
for i in L[:10] + ['...'] + L[-10:]:
print(i)
total permutations: 455
(0, 0, 0, 0, 0, 1, 4)
(0, 0, 0, 0, 0, 2, 3)
(0, 0, 0, 0, 0, 3, 2)
(0, 0, 0, 0, 0, 4, 1)
(0, 0, 0, 0, 1, 0, 4)
(0, 0, 0, 0, 1, 1, 3)
(0, 0, 0, 0, 1, 2, 2)
(0, 0, 0, 0, 1, 3, 1)
(0, 0, 0, 0, 1, 4, 0)
(0, 0, 0, 0, 2, 0, 3)
...
(3, 1, 0, 0, 1, 0, 0)
(3, 1, 0, 1, 0, 0, 0)
(3, 1, 1, 0, 0, 0, 0)
(3, 2, 0, 0, 0, 0, 0)
(4, 0, 0, 0, 0, 0, 1)
(4, 0, 0, 0, 0, 1, 0)
(4, 0, 0, 0, 1, 0, 0)
(4, 0, 0, 1, 0, 0, 0)
(4, 0, 1, 0, 0, 0, 0)
(4, 1, 0, 0, 0, 0, 0)

enumerating strings of legnth K from an alphabet

I have two elements, let's say [0,1] and I want to construct all possible combinations of length 2k with the same number of these two elements. For example, let 2k=6 and our output should be like (0,0,0,1,1,1) ,(0,0,1,0,1,1),(1,1,1,0,0,0) etc.
I was trying to use something like this [x for x in itertools.product([1,0], repeat=6)] but it gives me all possible sequences(the number of ones and zeros may not be the same). Is it possible to somehow immediately create a list with a given property?
Try itertools.permutations, like below:
import itertools
def perms(k):
l=k//2*[1] + k//2 * [0]
m=[i for i in itertools.permutations(l)]
return list(set(m))
Output for k=6:
>>> perms(6)
[(0, 1, 1, 0, 0, 1), (0, 1, 0, 1, 1, 0), (0, 1, 0, 0, 1, 1), (1, 1, 0, 0, 1, 0), (1, 1, 1, 0, 0, 0), (1, 0, 1, 0, 1, 0), (0, 0, 0, 1, 1, 1), (1, 0, 0, 1, 0, 1), (0, 1, 1, 0, 1, 0), (0, 0, 1, 1, 0, 1), (1, 1, 0, 1, 0, 0), (0, 1, 0, 1, 0, 1), (1, 1, 0, 0, 0, 1), (1, 0, 1, 1, 0, 0), (1, 0, 0, 0, 1, 1), (1, 0, 1, 0, 0, 1), (0, 0, 1, 0, 1, 1), (1, 0, 0, 1, 1, 0), (0, 1, 1, 1, 0, 0), (0, 0, 1, 1, 1, 0)]
The code can be adjusted to work with more general structures (more elements, other than [0,1] etc. Let me know if you need any help with that.
Saying a list of length 2k with equal number of elements [a, b] is equivalent to saying you want to a list with a in k positions and b in the other. So we can generate a list full of a's or b's and find all the possible combinations how to put k elements of the other variable in this list. This set of possible combinations is the same as selecting a set of k indices from the range [0, ..., 2k]. For the mathematics around this see [1].
from itertools import combinations
k = 6
assert k // 2
a = 0
b = 1
l = [
[a if i in combination else b for i in range(k)]
for combination in combinations(range(k), int(k/2))
]
[1] https://en.wikipedia.org/wiki/Combination

How to get a certain index of an item after using product

So this is what I have so far:
def createCombo(self):
usedAtoms = {'C':(0,101),'H':(0,201),'O':(0,4),'N':(0,4),'S':(0,4)}
MolecularFormula.combinations(self, usedAtoms)
def combinations(self,dicts):
product = [x for x in itertools.product(*[range(*x) for x in dicts.values()])]
print product
##print [dict(zip(dicts.keys(), p)) for p in product],
it ends up printing something out like this:
[(0, 0, 0, 0, 0), (0, 0, 0, 0, 1), (0, 0, 0, 0, 2), (0, 0, 0, 0, 3), (0, 0, 0, 1, 0), (0, 0, 0, 1, 1), (0, 0, 0, 1, 2), (0, 0, 0, 1, 3), (0, 0, 0, 2, 0), (0, 0, 0, 2, 1)
which is what I want it to print out, but how would I go about grabbing a certain index of an individual one in one of these products?
so like if I wanted to grab the 3 from this: (0, 0, 0, 0, 3)
?
In [1]: product = [(0, 0, 0, 0, 0), (0, 0, 0, 0, 1), (0, 0, 0, 0, 2), (0, 0, 0,
...: 0, 3), (0, 0, 0, 1, 0), (0, 0, 0, 1, 1), (0, 0, 0, 1, 2), (0, 0, 0, 1,
...: 3), (0, 0, 0, 2, 0), (0, 0, 0, 2, 1)]
In [2]: product[3][4] # get the fifth value of the fourth element of 'product'
Out[2]: 3

Strange list outputs in Sage

Consider the following two lines of code:
For t a dictionary, t = {1: (1, 0, 0, 0, 0, 0, 0, 0, 0), 2: (1, 1, 1, 1, 1, 1, 1, 1, 0)}, when I try to do: list(t[1]) to convert the tuple to a list, it gives me the output [(0,1)]. But when I do list(1,0,0,0), it gives me (as it should) [1,0,0,0]. What is going wrong here?
Entire Transcript
# given a prime p, return all A_n representations of dimension = p^2
def rankrep(p):
bound = p*p
s = SymmetricFunctions(QQ).schur()
Sym_p = s[p]
A = lambda i: WeylCharacterRing("A{0}".format(i))
deg = []
index = []
L = []
for i in xrange(bound):
deg.append([])
fw = A(i+1).fundamental_weights()
temp = A(i+1)
for j in fw.keys():
deg[i].append(temp(fw[j]).degree())
if temp(fw[j]).degree() == bound:
index.append('A'+str(i+1)+'(fw['+str(j)+'])')
L.append(fw[j])
return index, deg, L
def make_vars2(L):
return dict(enumerate(L, start=1))
[index, deg, L] = rankrep(3)
t = make_vars2(L)
print(t[1])
print t
list(t[1])
gives me
(1, 0, 0, 0, 0, 0, 0, 0, 0)
{1: (1, 0, 0, 0, 0, 0, 0, 0, 0), 2: (1, 1, 1, 1, 1, 1, 1, 1, 0)}
[(0, 1)]
Even though your t looks like it's a dictionary with integer keys and tuples of integer values, that's not what it is:
sage: t
{1: (1, 0, 0, 0, 0, 0, 0, 0, 0), 2: (1, 1, 1, 1, 1, 1, 1, 1, 0)}
sage: map(type, t)
[int, int]
sage: map(type, t.values())
[sage.combinat.root_system.ambient_space.AmbientSpace_with_category.element_class,
sage.combinat.root_system.ambient_space.AmbientSpace_with_category.element_class]
sage: parent(t[1])
Ambient space of the Root system of type ['A', 8]
If you want to get at the vector of coefficients, you can use .to_vector(). For example, we have
sage: t[1]
(1, 0, 0, 0, 0, 0, 0, 0, 0)
sage: type(t[1])
<class 'sage.combinat.root_system.ambient_space.AmbientSpace_with_category.element_class'>
sage: list(t[1])
[(0, 1)]
but
sage: t[1].to_vector()
(1, 0, 0, 0, 0, 0, 0, 0, 0)
sage: type(t[1].to_vector())
<type 'sage.modules.vector_rational_dense.Vector_rational_dense'>
sage: list(t[1].to_vector())
[1, 0, 0, 0, 0, 0, 0, 0, 0]

Categories

Resources