Python Forum
Giving all possible values to four different variables - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Giving all possible values to four different variables (/thread-32049.html)



Giving all possible values to four different variables - quest_ - Jan-17-2021

I have for different values which are a b c d. Their sum should be always 1
And they can take 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 but the sum always should be 1. and they can take same values too.
I want to print all possible combinations for these 4 variables like that:

a, b, c, d = 0.5, 0.2, 0.2, 0.1
a, b, c, d = 1.0, 0.0, 0.0, 0.0
a, b, c, d = 0.5, 0.0, 0.4, 0.1
.
.
.
How can I do that in simplest way?


RE: Giving all possible values to four different variables - Serafim - Jan-17-2021

The most obvious way (and ugliest, I guess):
>>> for a in range(11):
...     for b in range(11):
...         for c in range(11):
...             for d in range(11):
...                 if a+b+c+d == 10:
...                     print(a/10, b/10, c/10, d/10)



RE: Giving all possible values to four different variables - quest_ - Jan-17-2021

(Jan-17-2021, 09:45 PM)Serafim Wrote: The most obvious way (and ugliest, I guess):
>>> for a in range(11):
...     for b in range(11):
...         for c in range(11):
...             for d in range(11):
...                 if a+b+c+d == 10:
...                     print(a/10, b/10, c/10, d/10)

Thank you very much but I really do not want to use 4 for loop Because it is a part of a very long code and 4 for loop will make it code much more longer


RE: Giving all possible values to four different variables - bowlofred - Jan-17-2021

Yeah, this is small enough that there's only 11^4, or less than 15000. So brute-force is fine. You could instead brute-force through the first 3, then pick the 4th that matches.

from itertools import product

items = [x/10 for x in range(11)]

matching_sets = (x for x in product(items, repeat=4) if 0.99 < sum(x) < 1.01)
for answer in matching_sets:
    print(f"a, b, c, d = {', '.join(str(x) for x in answer)}")



RE: Giving all possible values to four different variables - quest_ - Jan-17-2021

(Jan-17-2021, 09:54 PM)bowlofred Wrote: Yeah, this is small enough that there's only 11^4, or less than 15000. So brute-force is fine. You could instead brute-force through the first 3, then pick the 4th that matches.

from itertools import product

items = [x/10 for x in range(11)]

matching_sets = (x for x in product(items, repeat=4) if 0.99 < sum(x) < 1.01)
for answer in matching_sets:
    print(f"a, b, c, d = {', '.join(str(x) for x in answer)}")

I now wrote this code:

import itertools
for four in itertools.product([0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9, 1.0], repeat=4): 
    a,b,c,d = four[0],four[1],four[2],four[3]
    if a+b+c+d ==1:
        print (a,b,c,d)
Which one is better/efficient?


RE: Giving all possible values to four different variables - bowlofred - Jan-17-2021

Beware floating point math. Many decimals cannot be represented exactly. Either check for approximate solutions, or do your math with integers and then divide by 10 later. Otherwise you will run into problems.

>>> 0.3 + 0.3 + 0.3 + 0.1 == 1.0
False
Workaround 1
>>> 3 + 3 + 3 + 1 == 10
True
Workaround 2
>>> 0.99 < 0.3 + 0.3 + 0.3 + 0.1 < 1.01
True
Workaround 3
>>> decimal.Decimal('0.3') + decimal.Decimal('0.3') + decimal.Decimal('0.3') + decimal.Decimal('0.1') == decimal.Decimal('1.0')
True



RE: Giving all possible values to four different variables - quest_ - Jan-17-2021

(Jan-17-2021, 10:28 PM)bowlofred Wrote: Beware floating point math. Many decimals cannot be represented exactly. Either check for approximate solutions, or do your math with integers and then divide by 10 later. Otherwise you will run into problems.

>>> 0.3 + 0.3 + 0.3 + 0.1 == 1.0
False
Workaround 1
>>> 3 + 3 + 3 + 1 == 10
True
Workaround 2
>>> 0.99 < 0.3 + 0.3 + 0.3 + 0.1 < 1.01
True
Workaround 3
>>> decimal.Decimal('0.3') + decimal.Decimal('0.3') + decimal.Decimal('0.3') + decimal.Decimal('0.1') == decimal.Decimal('1.0')
True

Many thanks, I did not notice that before!!!


RE: Giving all possible values to four different variables - deanhystad - Jan-18-2021

Use integer 0 through 10 and convert to float when the values are used.
import itertools
four = []
for a, b, c in itertools.product(range(11), repeat=3):
    if (d := 10 - a - b - c) >= 0:
        four.append([a, b, c, d]) # <- Can convert to float here or when used
This code generates 1331 combinations of which 286 are valid.

If you want to be really efficient you can do this:
for a in range(11):
    for b in range(11-a):
        for c in range(11-a-b):
            four.append([a, b, c, 10-a-b-c])
The inner loop executes 286 times to give you the 286 possible number combinations.