0

I have a list of lists made with

itertools.product(range(5), repeat=3)

which gives

[[0 0 0]
 [0 0 1]
 [0 0 2]
 [0 0 3]
 [0 0 4]
 [0 1 0]
 [0 1 1]
... etc]

I want to remove all lists that have common integer factors except the trivial cases of 0 and 1 because then that would match all lists. For example [0 0 2] is [0 0 1] multiplied by 2 so I'd want to remove [0 0 2]. Another example would be [3 3 3] which is [1 1 1] multiplied by 3 so I'd want to remove [3 3 3]. What is the most efficient way to do this?

cpc333
  • 1,493
  • 1
  • 11
  • 10
  • Remove them all because any integer triple has a common factor of 1, which is an integer. – gilch Jul 07 '19 at 19:06
  • Ya, maybe should have mentioned except 0 and 1, which are trivial cases because then you'd have nothing left. – cpc333 Jul 07 '19 at 19:06

2 Answers2

3

It sounds like you want all the combinations that don't share a common factor (other than 1, obviously). For example: [2, 3, 4] should be in your list because you can't factor a single number shared by all of them other than one. [2,4,0] on the other hand can be thought of as 2 * [1, 2, 0]. You can use math.gcd to find the GCD — GCD is associative, so you can nest it (or use reduce() for a general solution).

from itertools import product
from math import gcd
from functools import reduce

test = lambda p: reduce(gcd, p) == 1

[p for p in product(range(5), repeat=3) if test(p)]

Result

[(0, 0, 1),
 (0, 1, 0),
 (0, 1, 1),
 (0, 1, 2),
 (0, 1, 3),
 (0, 1, 4),
 (0, 2, 1),
 (0, 2, 3),
 ...
 (4, 2, 3),
 (4, 3, 0),
 (4, 3, 1),
 (4, 3, 2),
 (4, 3, 3),
 (4, 3, 4),
 (4, 4, 1),
 (4, 4, 3)]

Because of the way gcd works you will need to treat [0,0,0] as a special case.

Mark
  • 90,562
  • 7
  • 108
  • 148
  • Would this still work if each list had 4 elements instead of 3? Eg. [[0 0 0 1], [0 0 0 2], etc...] – cpc333 Jul 07 '19 at 19:40
  • @cpc333, yes the same basic idea should work, but you need to add another nesting of `gcd()`. If your number of elements groups these nested calls will get a little unwieldy. At some point you will probably want a proper function that can handle any number of args and return whether they share a common divisor. – Mark Jul 07 '19 at 19:43
  • @cpc333 here's [a thread](https://stackoverflow.com/questions/16628088/euclidean-algorithm-gcd-with-multiple-numbers) with some tips on calculating gcd of multiple numbers. – Mark Jul 07 '19 at 19:44
  • Right, actually I need the case of N elements. That thread helped. Thanks! – cpc333 Jul 07 '19 at 19:47
  • @cpc333 -- I edited this for a common solution based on one of those. – Mark Jul 07 '19 at 19:48
0

Creating list with itertools.product() and removing items you don't need is inefficient by itself: it would be better to skip those items at the list generation phase.

But if you want to remove items anyway, you can use approach similar to Sieve of Eratosthenes:

Take some list, for example (0,0,1), muliple it by 2 - you get (0,0,2) - remove it. Then multiply by 3 - you get (0,0,3) - remove it as well. Then do the same with multiplier 4 and 5. If any of such lists were found, remove original list as well.

Take next item of modified list of lists and repeat the process.

In the simpliest approach you may try multipliers from 2 to 5 all the time. If you want to optimize it, you may first find max value and check up to 5//max_value only.