6
\$\begingroup\$

I'm trying to strip down my python code to be as few lines as possible. The task: count how many square numbers are below 100. Here's my code so far:

m = 0
for x in range(0, 100):
    m+=1-(-((-((x+1)**(0.5)-((x+1)**(0.5))//1))//1));
print(m)

That addition statement adds 1 to m (the counter) only when (x+1) is a perfect square. Is it possible to shorten anything? Maybe find a way to print without using a counter -- such as printing a summation in a form such as:

print(sum(min,max,variable,statement))
\$\endgroup\$
  • 9
    \$\begingroup\$ print(9) works :P \$\endgroup\$ – ASCII-only Apr 7 '17 at 3:33
  • 10
    \$\begingroup\$ To close voters: [tips] are on topic. \$\endgroup\$ – Rɪᴋᴇʀ Apr 7 '17 at 3:34
  • \$\begingroup\$ I mean, you can get rid of the semicolon on your third line. \$\endgroup\$ – Ben Frankel Apr 7 '17 at 3:35
  • 1
    \$\begingroup\$ You say you want to count how many square numbers are below 100, but you're counting how many are between 1 and 100 inclusive. Which is it? \$\endgroup\$ – Ben Frankel Apr 7 '17 at 3:42
  • 4
    \$\begingroup\$ Have you taken a look at out Python golf tips? In particular, there's some easy gains from removing whitespace and parentheses. I think asking for particular advice for this particular golf is putting the cart before the horse. \$\endgroup\$ – xnor Apr 7 '17 at 3:45
3
\$\begingroup\$

For the exact question posed: since we know that 1 is a perfect square and all integers between that and the maximal one (here 9) will be included we can simply find that maximal one:

print((100-1)**.5//1)

(//1 performing integer division by one to remove any fractional part may be replaced with /1 prior to Python 3.)

with both endpoints (an inclusive start and exclusive stop equivalent to a range) this could be extended to a function (negative inputs catered for with max):

f=lambda start, stop:print(max(0,stop-1)**.5//1-max(0,start)**.5//1)
\$\endgroup\$
  • \$\begingroup\$ Ah, that's a good bit of math to solve the problem. Well done. \$\endgroup\$ – Graviton Apr 7 '17 at 4:12
2
\$\begingroup\$

For the record, below is another approach using additions and multiplications only.

The square of N is the sum of the N first odd positive integers:

1^2 = 1
2^2 = 1 + 3 = 4
3^2 = 1 + 3 + 5 = 9
4^2 = 1 + 3 + 5 + 7 = 16
etc.

Consequently, if we are to compute all perfect squares up to a given limit, each one can be quickly deduced from the previous one.

Hence the following possible algorithms:

# with 3 variables, using addition only
s = i = 1
n = 0

while s < 100:
  n += 1
  i += 2
  s += i

print(n)
# with 2 variables, using addition and multiplication
s = 1
n = 0

while s < 100:
  n += 1
  s += n * 2 + 1

print(n)

Or as a recursive lambda:

f = lambda x, s=0, n=0: f(x, s+n*2+1, n+1) if s < x else n-1

print(f(100))
\$\endgroup\$
1
\$\begingroup\$

This works (47 chars):

print(sum(map(lambda n:0==n**.5%1,range(100))))

n**.5 will return a float, which will be a whole number if n is a perfect square. We can then do %1 to get the fractional part, which will be 0 if n is a perfect square, so adding 0== will give us a boolean of whether or not n is a perfect square.

We can then make that into a lambda function and map that onto the range, which will give us a list of booleans, which can be summed to give us how many True values were there.

As in Ben Frankel's answer, it's actually shorter to use list comprehension than map. I didn't think of that. That gets us down to 41 chars.

print(sum(0==n**.5%1for n in range(100)))

EDIT: removed one byte by replacing not with 0==

\$\endgroup\$
0
\$\begingroup\$

How about this?

print(sum(x==int(x**.5)**2for x in range(1,101)))

This is a sum of boolean values, so they are treated as 0 for False and 1 for True.

EDIT: As in Riker's answer, x**.5%1==0 is shorter than x==int(x**.5)**2.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.