Python 3 - Tried Golfing My Assignment

9

Note: This isn't as much a golfing challenge; it is more so asking for golfing suggestions.

Recently I had a Python assignment for my web development class, in order to check whether we could code. Since I already feel comfortable in Python, I decided to try and golf it, and I was wondering if people could point out things that I missed.

I already know that there are extra spaces in some places, but I'm more interested in conceptual things, like using while r: when r is a variable, and then waiting for it to "run out"!

The assignment

import random
from collections import Counter
s=l=''
c=['yellow','blue','white','green','Black', 'purple', 'silver', 'cyan', 'magenta', 'red']
n=[10,15,1,10,6,15,10,25,1,12,5,10,4,6,5,12,0,10,1,1]
o=i=0
for y in c:l+=y[0]*(random.randint(n[o],n[o+1]));o+=2
l=list(l)              
print("Welcome to the CIMS Gumball Machine Simulator\nYou are starting with the following gumballs:")
for b in c:print(str(l.count(b[0])) + " "+b);random.shuffle(l)
print("Here are your random purchases:")
while 'r' in l:
    random.shuffle(l); r=l.pop(); s+=r
    for j in c:
        if j[0] == r:print(j.capitalize())
print("You purchased %i gumballs, for a total of $%.2f \nMost common gumball(s):" % (len(s),len(s)*25/100))
a=Counter(s).most_common()
m=[x[1] for x in a]
while m[0] == m[i]:
    for j in c:
        if j[0] == a[i][0]:print(j.capitalize(), end=" ")
if(i<(len(m)-1)):i+=1
else:break

Also: I'm sorry if this isn't an appropriate question for the code golf page, since it is not a challenge and will remove it on request.

aks.

Posted 2015-02-24T04:04:24.433

Reputation: 654

Putting the issue of on-topic-ness aside (since I'm not sure), perhaps take a look at the Python golf tips page? Also, which Python version? (I'm assuming 3 due to the parens around print, but just to check)

– Sp3000 – 2015-02-24T04:15:37.417

5Have you attempted to golf it yet? – feersum – 2015-02-24T04:18:12.070

2This code has a lot of simple golf improvements remaining. I think you'd learn better if you reviewed the golf tips and looked at other Python golfs, and did more to shorten it your code on your own. Then, if you post what you get, people can give more insightful advice. – xnor – 2015-02-24T06:40:02.233

Answers

20

Here's a whole bunch of micro-optimisations you can do:

Use .split() to create a long list (-17 bytes):

c=['yellow','blue','white','green','Black', 'purple', 'silver', 'cyan', 'magenta', 'red']
c='yellow blue white green Black purple silver cyan magenta red'.split()

Remove extraneous brackets (-2 bytes):

l+=y[0]*(random.randint(n[o],n[o+1]))
l+=y[0]*random.randint(n[o],n[o+1])

Use splat (-2 bytes):

random.randint(n[o],n[o+1])
random.randint(*n[o:o+2])

Use extended iterable unpacking to turn something into a list (-4 bytes):

l=list(l)
*l,=l

Import all the things (-15 bytes):

import random;random.randint;random.shuffle;random.shuffle
from random import*;randint;shuffle;shuffle

Use other functions that can do the same job here (-5 * 2 = -10 bytes):

j.capitalize()
j.title()

print separates by space by default (-11 bytes):

print(str(l.count(b[0])) + " "+b)
print(l.count(b[0]),b)

More unpacking (-3 bytes):

r=l.pop()
*l,r=l

Abuse side-effects (-1 byte, plus indents):

if j[0]==r:print(j.capitalize())
r!=j[0]or print(j.capitalize())

Anything reused and over 5 chars might be worth saving as a variable (-1 byte):

len(s);len(s)
L=len(s);L;L

Simplify fractions (-5 bytes):

len(s)*25/100
len(s)/4

Unary abuse (-4 bytes):

if(i<(len(m)-1)):i+=1
if~-len(m)>i:i+=1

Or the biggest one of all...

Look at your algorithm, and see if it needs changing altogether

from random import*
*s,P,S=print,shuffle
P("Welcome to the CIMS Gumball Machine Simulator\nYou are starting with the following gumballs:")
*l,c,C='yellow blue white green Black purple silver cyan magenta red'.split(),s.count
for x,y,z in zip(c,[10,1,6,10,1,5,4,5,0,1],[15,10,15,25,12,10,6,12,10,1]):n=randint(y,z);l+=[x]*n;P(n,x)
S(l)
P("Here are your random purchases:")
while'red'in l:S(l);*l,r=l;s+=r,;P(r.title())
L=len(s)
P("You purchased %i gumballs, for a total of $%.2f\nMost common gumball(s):"%(L,L/4))
for x in c:C(x)!=max(map(C,c))or P(x.title())

(If you ever find yourself importing Counter in a code-golf, you're probably doing something very wrong...)

Sp3000

Posted 2015-02-24T04:04:24.433

Reputation: 58 729

Wow!! This is exactly what I was looking for. Thanks so much for your help! – aks. – 2015-02-24T05:53:44.913

You could probably obviate the need for .title() by precapitalizing everything. Also, assign s.count to a variable. – isaacg – 2015-02-24T05:57:07.893

@isaacg I thought I'd try to keep the functionality of the original program. If the spec was all that counted, I'd drop a few of the long print statements since technically the assignment doesn't need them ;) – Sp3000 – 2015-02-24T05:58:59.857

@Sp3000 In that case, why not put the .title() on the initial string? Saves one .title() use. – isaacg – 2015-02-24T05:59:42.697

@isaacg Also, I did it by picking out of an array of each of the starting letters, and 'b' represented blue and 'B' represented black – aks. – 2015-02-24T06:02:43.363

Thanks again @Sp3000... This is the coolest thing to see ever, not to mention incredibly educational! – aks. – 2015-02-24T06:05:39.127

@aks. No worries, although I'm not sure about the fast accept (it hasn't been very long). I'm sure there's a lot more things that can be done, and other people probably have great ideas too, but I hope I've gotten my main point across :) – Sp3000 – 2015-02-24T06:07:06.967

@Sp3000 okay I'll let it hang around a little longer... Although I wasn't expecting anything more than this and I think the other golfers should focus on real golf challenges – aks. – 2015-02-24T06:09:49.567

Hey @Sp3000, is there a way of simplifying l=list;*x,=input() into one equals operation? – aks. – 2015-02-26T20:10:08.103

In Python 3, I couldn't get it to work. – aks. – 2015-02-26T20:10:33.103

I'm trying to get a list of each character in the input, not just a list of the input – aks. – 2015-02-26T20:16:11.647

@aks. Not that I can think of at least, because by putting two things on the right hand side (e.g. l,*x=list,input()) you turn the right hand side into a tuple, which it traverses over (given the string in a list), rather than a string (which allows turning the string into a list of chars). – Sp3000 – 2015-02-26T22:59:50.560