0

Consider list(range(0, 5)), for example. I want the function to do this mapping:

(1, 4), (2, 1), (3, 2), (4, 3)

That is, it should return the previous value on the list and, if it can't do that (if it reaches index 0), it will "loop around" and output the list's last value.

I made this ugly solution:

def come_back(x, highest, head = 1):
    if x == head:
        newx = highest
    else:
        newx = x - 1
    return newx

But it feels like there should be a more elegant one, probably based on Modular Arithmetic. Any clues?

2 Answers2

0

Here's how I would consider doing it:

def rotate_one(l: list) -> list:
    return [l[-1], *l[:-1]]

values = list(range(1, 5))
result = list(zip(values, rotate_one(values)))
print(values)  # [1, 2, 3, 4]
print(result)  # [(1, 4), (2, 1), (3, 2), (4, 3)]
0x5453
  • 12,753
  • 1
  • 32
  • 61
0

Using the mod of the current index i:

data[(i-1) % len(data)]

should give you what you want.

data = ["one", "two", "three", "four"]
data_length = len(data)
result = [
  (data[i], data[(i-1) % data_length])
  for i
  in range(data_length)
]
print(result)

In fact, as @kaya3 astutely observes, mod is not needed here due to negative indexing support in python and we can do:

data[i-1]

then our solution might simplify to:

data = ["one", "two", "three", "four"]
result = [(data[i], data[i-1]) for i in range(len(data))]
print(result)

either should give you:

[('one', 'four'), ('two', 'one'), ('three', 'two'), ('four', 'three')]
JonSG
  • 10,542
  • 2
  • 25
  • 36
  • 1
    Note that you don't actually need the `% data_length` in this case, because `data[-1]` is equivalent to `data[data_length - 1]` due to how negative indices work in Python. Though you may prefer to write the modulo in order to be explicit. – kaya3 Jan 06 '23 at 15:17
  • good call on that observation – JonSG Jan 06 '23 at 15:18