# How to shorten Python code involving the sum of reciprocals?

I have a coding problem that goes like this:

Given a positive integer $$\N\$$, return a list of all possible pairs of positive integers $$\(x,y)\$$ such that $$\frac1x+\frac1y=\frac1N$$

I already solved the problem using Python, but I was wondering how I can code golf it. The following is my attempt at golfing (I try to follow some tips on the tips page):

108 bytes

exec("f=lambda N:[b for i in range(1,N+1)if N*N%i==0"+"for b in[%s,%s[::-1]]][:-1]"%(("[N+i,N+N*N//i]",)*2))


Try it online!

def f(N):
l=[]
for i in range(1,N+1):
if N*N%i==0:
a=[N+i,N+N*N//i]
l.extend([a,a[::-1]])
return l[:-1]


Try it online!

• Out of curiosity, is this a planned code-golf challenge? Not that I'm gonna plan a solution in advance, but it seems like a real nice challenge. Jan 29, 2022 at 17:27
• @ThisFieldIsRequired No, I was just wondering how I can golf my own code for this problem. Jan 29, 2022 at 17:28
• @AnttiP That works too... I guess I immediately approached the problem mathematically without thinking of brute force solutions. Jan 29, 2022 at 17:50
• Small correction: f=lambda N:[(x,y)for x in range(1,N**3)for y in range(N**3)if(x+y)*N==x*y] Jan 29, 2022 at 17:59

# Python 3.8 (pre-release), 60 bytes

f=lambda N:[[N+i,N+N*N//i]for i in range(1,N*N+1)if 1>N*N%i]


Try it online!

No need for reversing:

We just generate every fraction for which the first denominator is a divisor of N squared.

• Oh yeah, I guess I got tunnel vision with the reversing thing. Also the if 1>N*N%i is pretty smart too. Jan 29, 2022 at 17:57
• // can be / in Python 2 for -1 byte Jan 29, 2022 at 17:59
• @pxeger Yep! but I don't do python 2. Jan 29, 2022 at 18:00
• That just output 30.0 instead of 30 but maybe still reasonable?
– l4m2
Jan 29, 2022 at 18:07
• @AnttiP So, maybe 3**N?
– tsh
Jan 30, 2022 at 2:29

As AnttiP has pointed out, this can be shorter with a change of approach and full rewrite. Let's look at some simpler manipulations of your original code though just for the sake of it though:

Here was my first attempt at eliminating the exec hack:

### 85 bytes

lambda N:[b for i in range(1,N+1)if N*N%i==0for b in[A:=[N+i,N+N*N//i],A[::-1]]][:-1]

Attempt This Online!

Unfortunately, as you may notice, it doesn't work, because := is not allowed in for comprehension iterable expression.

There's another place we can put it in though: the if clause just before it:

### 91 bytes

lambda N:[b for i in range(1,N+1)if(A:=[N+i,N+N*N//i])and N*N%i==0for b in[A,A[::-1]]][:-1]

Attempt This Online!

This can be shortened a bit by combining the comparison ==0:

### 89 bytes

lambda N:[b for i in range(1,N+1)if 0in(A:=[N+i,N+N*N//i],N*N%i)for b in[A,A[::-1]]][:-1]

Attempt This Online!

The [:-1] at the end is just to remove the final duplicated result of (x, x), but we can remove this just by switching to a set comprehension (and using a tuple instead of a list, because it's hashable):

### 84 bytes

lambda N:{b for i in range(1,N+1)if 0in(A:=(N+i,N+N*N//i),N*N%i)for b in[A,A[::-1]]}

Attempt This Online!

The output is no longer in order, so hopefully that doesn't matter here.

I'm working on going further than this... stay tuned

• That's a nice trick to take out the walrus operator from the iterable expression! I couldn't figure out how to do that, so I resorted to the exec trick. Jan 29, 2022 at 17:53