A.
Here's a simple one-liner:
>>> c, r = 10, 3
>>> sorted(range(c-r, c+r+1), key=lambda n: (abs(c-n), -n))
[10, 11, 9, 12, 8, 13, 7]
range() can easily give us the numbers we need but to get them in the right order, sort each by its distance from the center c, using abs(). And to get the larger neighbour before the smaller in that pair (11 before 9), use -n which is more negative (smaller) for the larger neighbours.
If you want the smaller neighbour before the larger one, then flip the sign:
>>> sorted(range(c-r, c+r+1), key=lambda n: (abs(c-n), n))
[10, 9, 11, 8, 12, 7, 13]
In a generator:
def generateNeighborhood(c: int, r: int):
yield from sorted(range(c-r, c+r+1), key=lambda n: (abs(c-n), -n))
But note that sorted() returns a list anyway, so may as well put return sorted(...). And for very very long lists (large radii r), use (B) a modified version of your original code or (C) the variation below it:
B.
As user3386109 suggested in the comments, you can remove the j loop and yield the neighbours for that radius:
def generateNeighborhood(c: int, r: int):
yield c
for i in range(1, r + 1):
yield c + i
yield c - i
C.
Here's a variation, with generator expressions:
def generateNeighborhood(c: int, r: int):
yield c
pairs = ((c + i, c - i) for i in range(1, r + 1)) # generator, not expanded here
yield from (n for pair in pairs for n in pair) # processed one at a time
Performance with small and large radii:
Small: list(generateNeighborhood(10, 3)) - B is faster than A is faster than C
- B: 1.19 µs
- A: 2.53 µs
- C: 2.6 µs
Large: list(generateNeighborhood(10, 3_000_000)) - B is faster than C is faster than A:
- B: 877 ms
- C: 1.43 s
- A: 2.97 s
So for simplicity, go with A. For speed, go with B. (I thought C would beat B but it doesn't.)