-4

I am trying to build a 2d list of test cases that contains all the possible cases ('+', '-', '*', '/') like this:

[('+', '+', '+', '+'),
 ('+', '+', '+', '-'),
 ('+', '+', '+', '/'),
 ('+', '+', '+', '*'),
 ('+', '+', '-', '-'),
 ('+', '+', '-', '/'),
 ('+', '+', '-', '*'),
 ('+', '+', '/', '/'),
 ('+', '+', '/', '*'),
 ('+', '+', '*', '*'),
 ('+', '-', '-', '-'),
 ('+', '-', '-', '/'),
 ('+', '-', '-', '*'),
 ('+', '-', '/', '/'),
 ('+', '-', '/', '*'),
 ('+', '-', '*', '*'),
 ('+', '/', '/', '/'),
 ('+', '/', '/', '*'),
 ('+', '/', '*', '*'),
 ('+', '*', '*', '*'),
 ('-', '-', '-', '-'),
 ('-', '-', '-', '/'),
 ('-', '-', '-', '*'),
 ('-', '-', '/', '/'),
 ('-', '-', '/', '*'),
 ('-', '-', '*', '*'),
 ('-', '/', '/', '/'),
 ('-', '/', '/', '*'),
 ('-', '/', '*', '*'),
 ('-', '*', '*', '*'),
 ('/', '/', '/', '/'),
 ('/', '/', '/', '*'),
 ('/', '/', '*', '*'),
 ('/', '*', '*', '*'),
 ('*', '*', '*', '*')]

I am thinking to create it in a Python list comprehension. I tried:

[[x] * 4 for x in ('+','-','*', '/')]

but the result is not something I want. Anyone knows how to do it? Thanks.

Ken
  • 1,234
  • 10
  • 16
  • Running `[[x] * 4 for x in ('+','-','*', '/')]` gave me `[['+', '+', '+', '+'], ['-', '-', '-', '-'], ['*', '*', '*', '*'], ['/', '/', '/', '/']]`, as expected. What exactly do you want? – TheTridentGuy supports Ukraine May 21 '23 at 16:37
  • 2
    Take a look at itertools.product(), possibly (comment instead of answer because I'm not sure I'm actually clear on what you are trying to do) – Wooble May 21 '23 at 16:37
  • 1
    FWIW I don't think the linked dupe is quite the same: I think @Ken wants repeated elements, rather than just the product (although you can also get this with itertools.product with a bit more work). – 2e0byo May 21 '23 at 16:42
  • @Ken IMHO this coded as a low-quality question but was actually perfectly answerable (hence I answered it, and I didn't downvote FWIW). Had you stated 'all possible combinations with length 4, ignoring order' it probably wouldn't have. In general the python tag is pretty trigger happy because so many beginners just dump the code on it: not ideal, but how it is. Another pointer---again I think wrongly in this case---for 'low quality' was the statement that your listcomp didn't work without saying why you thought it should. Again, had you said something like 'I want to write something.. [1/3] – 2e0byo May 21 '23 at 17:14
  • [2/3]... like this, but generating the intermediate values' it would have coded as a better question. Again plenty of people accuse syntax of 'not doing what I want' rather than asking 'how do I write code to do X in this style (which does Y, partially achieving X)'. FWIW I smiled at the phrase 'not something I want': to a native british speaker this is roughly equivalent to 'something I found in the drain', i.e. a strongly negative euphemism, and obviously not a simple attack on python. But I had to be awake enough to see that.... [2/3] – 2e0byo May 21 '23 at 17:18
  • @2e0byo, get it, will do it better next time. thanks for your help. – Ken May 21 '23 at 17:24
  • [3/3] OTOH, how are you supposed to get that right in a foreign language? To continue to give unsolicited advice: it might be worth (i) wording non-working attempts as 'I thought I could use something in the style of X, but how do I generate missing components Y'? which makes it clear *why* you're including non-working code, and (ii) stating the spec as rigorously as you can (e.g. 'four-tuples of all the elements in X repeated zero to four times ignoring order' is inelegant, but clear). Here you might want to type up a 2-long example, and say 'but with these 4 tokens'. – 2e0byo May 21 '23 at 17:24
  • although all that said I do think you have a fair criticism here: this tag *is* trigger-heavy. (It's also really heavily inundated, which is the flip side of the same problem.) – 2e0byo May 21 '23 at 17:25

1 Answers1

2

itertools.combinations_with_replacement?

In [1]: from itertools import combinations_with_replacement
In [2]: list(combinations_with_replacement(["+", "-", "/", "*"], 4))
Out[2]:
[('+', '+', '+', '+'),
 ('+', '+', '+', '-'),
 ('+', '+', '+', '/'),
 ('+', '+', '+', '*'),
 ('+', '+', '-', '-'),
 ('+', '+', '-', '/'),
 ('+', '+', '-', '*'),
 ('+', '+', '/', '/'),
 ('+', '+', '/', '*'),
 ('+', '+', '*', '*'),
 ('+', '-', '-', '-'),
 ('+', '-', '-', '/'),
 ('+', '-', '-', '*'),
 ('+', '-', '/', '/'),
 ('+', '-', '/', '*'),
 ('+', '-', '*', '*'),
 ('+', '/', '/', '/'),
 ('+', '/', '/', '*'),
 ('+', '/', '*', '*'),
 ('+', '*', '*', '*'),
 ('-', '-', '-', '-'),
 ('-', '-', '-', '/'),
 ('-', '-', '-', '*'),
 ('-', '-', '/', '/'),
 ('-', '-', '/', '*'),
 ('-', '-', '*', '*'),
 ('-', '/', '/', '/'),
 ('-', '/', '/', '*'),
 ('-', '/', '*', '*'),
 ('-', '*', '*', '*'),
 ('/', '/', '/', '/'),
 ('/', '/', '/', '*'),
 ('/', '/', '*', '*'),
 ('/', '*', '*', '*'),
 ('*', '*', '*', '*')]

This assumes, as @ayhan points out, that order doesn't matter. If order does matter, you just want the cartesian product, with a repeated input:

from itertools import product
list(product(["+", "-", "/", "*"], repeat=4))

combinations_with_replacement returns a subset of this, as the itertools docs note

The code for combinations_with_replacement() can be also expressed as a subsequence of product() after filtering entries where the elements are not in sorted order

From the provided 'equivalent' code you can also build up a pure python implementation. The trick is separating the multiplying of inputs from filtering the desired outputs: i.e. it's a two step, not one step process. (Albeit this first step can be done on the fly.)

2e0byo
  • 5,305
  • 1
  • 6
  • 26
  • 1
    This assumes order is not important (i.e. `('-', '/', '*', '*')` is the same as `('/', '*', '-', '*')`. The question is not exactly clear so I'll just leave the alternative here: `list(product(('+', '-', '*', '/'), repeat=4))` – ayhan May 21 '23 at 16:49
  • @ayhan yes, I hesitated between them: I'll edit the answer for completeness. – 2e0byo May 21 '23 at 17:02