0

I am trying to write using list comprehensions for the scenario.

I want fizzbuzz if it is divisible by both 3 and 5; fizz for divisble by 3 and buzz if divisible by 5.

It seems like in my logic I have to use else logic in the end using '' to get the output. if I don't use the last else I am getting an error. I am sure I am missing something silly.

['fizzbuzz' if (i%3==0 and i%5==0) else 'fizz' if i%3==0 else 'buzz'if i%5==0 else ''   for i in range(1,51) ]
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
datayogi
  • 1
  • 1
  • 6
    You know there are no prizes to be won for putting all logic in one line? ;-) – user2390182 Oct 14 '21 at 18:01
  • very true...just practicing list comprehensions. Thank you for the reminder! – datayogi Oct 14 '21 at 18:04
  • 1
    comprehension without else: https://stackoverflow.com/a/4260304/10703473 – Gary Oct 14 '21 at 18:10
  • 1
    Ternary statements have nothing to do with list-comprehensions, by the way. You can make a variable `('x' if test else ('other' if test2 else 'default')` – OneCricketeer Oct 14 '21 at 18:56
  • @OneCricketeer list comprehensions have special syntax for filtering conditional statements. https://realpython.com/lessons/filtering-elements-list-comprehensions/ Was required to answer the original question, although I don't think they are required anymore post-edit. – DivideByZero Oct 14 '21 at 18:57
  • @DivideByZero They do, but you cannot put an else on that. Question being asked didn't change – OneCricketeer Oct 14 '21 at 18:57
  • Question being asked changed when OP decided that they needed to add the current number into the list if it does not fulfill %3==0 or %5==0. Looks like they submitted their edit as an answer, though. – DivideByZero Oct 14 '21 at 19:18

2 Answers2

0

Sorry, I didn't read the question completely; if none of the scenarios match then we need to print the number. so the solution I wrote needed an 'i' to print in the default scenarios.

print(['fizzbuzz' if (i%3==0 and i%5==0) else 'fizz' if i%3==0 else 'buzz'if i%5==0 else i   for i in range(1,51) ])
Python learner
  • 1,159
  • 1
  • 8
  • 20
datayogi
  • 1
  • 1
  • Something that may (or may not) apply to your problem - you can print during list comprehension (as a very crude one-line for loop): [print(i) for i in range(100)] Note that your – DivideByZero Oct 14 '21 at 19:02
  • Or alternatively :-) [0 for i in range(100) if print(i)] Don't use this for anything important or you will traumatize people who have to read your code. – DivideByZero Oct 14 '21 at 19:03
  • @DivideByZero However, this should be avoided as a makes a pointless in-memory list of all None ... `if print(i)` will also always evaluate as falsy, so resulting in an empty list – OneCricketeer Oct 14 '21 at 19:03
  • @OneCricketeer Yep, totally agreed. Just sharing, it's useful for code golfing and debugging (and that's about it). – DivideByZero Oct 14 '21 at 19:05
0

Note: this answer was created before OP changed their question, so you might need to tweak the code you use. The process that you use will be very similar to the write-up below, so I figure I should keep this answer posted for now.

As a disclaimer, this answer is more from a code golf perspective than a practical perspective. Don't try to use this approach an actual project (or even a job interview) because your code will be too confusing to understand.

First, we need something to test our modifications against, because these modifications can be very error-prone. Feel free to ignore this, it's just so we can compare the list comprehensions we develop to the expected output:

list(filter(None, ['fizzbuzz' if (i%3==0 and i%5==0) else 'fizz' if i%3==0 else 'buzz'if i%5==0 else '' for i in range(1,51)]))

Now, let's try to make the comprehension shorter :)

You can apply a filter operation when constructing lists by placing an if statement on the right side of the range statement:

['fizzbuzz' if (i%3==0 and i%5==0) else 'fizz' if i%3==0 else 'buzz' for i in range(1,51) if (i%5==0 or i%3 == 0)]

It seems like you are trying to optimize for code length (which can be pretty fun sometimes so I totally get it). If this is the case, we can further reduce your comprehension.

First, Python evaluates 1 as true and 0 as false. This allows us to re-write (i%3==0 and i%5==0) as (not i%3 and not i%5).

Next, we can apply DeMorgan's Law:

(not i%3 and not i%5) EQUALS not (i%3 or i%5).

By applying this discovery we can get a decent character reduction in our original statement, which is pretty neat:

['fizzbuzz' if not (i%3 or i%5) else 'fizz' if i%3==0 else 'buzz' for i in range(1,51) if not (i%5 and i%3)]

Testing against the original spec we set up at the top:

list(filter(None, ['fizzbuzz' if (i%3==0 and i%5==0) else 'fizz' if i%3==0 else 'buzz'if i%5==0 else '' for i in range(1,9999)])) == ['fizzbuzz' if not (i%3 or i%5) else 'fizz' if i%3==0 else 'buzz' for i in range(1,9999) if not (i%5 and i%3)]
# evaluates to True :)

Another trick we can use to clean things up is the fact that Python allows us to multiply strings by integers (try in in interactive mode and see what happens):

['fizz'*(i%3==0) + 'buzz'*(i%5==0) for i in range(1,51) if not (i%5 and i%3)]

Testing against the original spec we set up at the top:

list(filter(None, ['fizzbuzz' if (i%3==0 and i%5==0) else 'fizz' if i%3==0 else 'buzz'if i%5==0 else '' for i in range(1,9999)])) == ['fizz'*(i%3==0) + 'buzz'*(i%5==0) for i in range(1,9999) if not (i%5 and i%3)]
# evaluates to True :)

If anybody can reduce the line count any further (without just shortening variables/whitespace), feel free to edit this answer, since that seems to be the goal for this question.

DivideByZero
  • 423
  • 6
  • 14