1

I am working on a problem that need me rotate the numbers at index[1] in a nested loop once toward the right. The nested loop looks like this [(1, 1), (2, 2), (3, 3), (4, 4), (1, 5)] and i want the nested loop to look like this [(1, 5), (2, 1), (3, 2), (4, 3), (1, 4)] (All the number at index[1] moved once to the right) I want to do this at a range of N times. I tried using deque from the module collections but it didn't do the thing i wanted. Here are my code.

from collections import deque
n = int(input())
a = [int(i) for i in input().split()]
s, f = map(int, input().split())
num = 0

sequence = [i for i in range(1, len(a) + 1)]
res = list(zip(a, sequence))
print(res)
for i in res:
    res1 = deque(i[1])
    res1.rotate(1)
    print(res1)

I got an error on line 11

   res1 = deque(i[1])
TypeError: 'int' object is not iterable
3
  • Your question is unclear. Show your and clarify your question Commented Aug 29, 2020 at 1:14
  • 1
    What's that about N times? Commented Aug 29, 2020 at 1:17
  • @superbrain i want to rotate the numbers at index[1] n times. But n could be any number Commented Aug 29, 2020 at 1:21

5 Answers 5

4

Could separate them into firsts and seconds, shift the seconds, and recombine:

a, b = zip(*lst)
lst = [*zip(a, b[-1:] + b[:-1])]

or just

a, b = zip(*lst)
lst = [*zip(a, b[-1:] + b)]

Use -n to rotate n steps (if n can be negative or longer than the list, take it modulo the length of the list first).

Sign up to request clarification or add additional context in comments.

2 Comments

list(zip(a, b[-1:] + b[:-1])) will do as the 2nd line, I think it's slightly more readable to use list(iterable) than it is to use [*iterable] as the syntax may confuse some devs that aren't used to it
@IainShelvington I used to think so, but I got used to [*iterable]. Maybe people will get more used to it over time (except those people who still write set([4, 2]) instead of {4, 2}).
2

It could be a one-liner:

[(x[0], y[1]) for x, y in zip(l, l[-1:] + l)]

but Superb rain's answer is more explicit/pythonic

1 Comment

Ha, I actually prefer yours. I think I just thought zip as soon as I saw those tuples, never even considering a list comp here.
0

Just for the sake of it - Optimized solution:

from collections import deque
def rotate_second_indices(lst, n=1):
    assert n < len(lst)
    buffer = deque(lst[i][1] for i in range(-n,0))
    for index, (a, b) in enumerate(lst):
        lst[index] = (a, buffer.popleft())
        buffer.append(b)

Original answer

That code should do it:

lst = [(1, 1), (2, 2), (3, 3), (4, 4), (1, 5)]
new = lst[-1][1]
for index, (first, second) in enumerate(lst):
    lst[index] = (first, new)
    new = second

Another option:

lst = [(1, 1), (2, 2), (3, 3), (4, 4), (1, 5)]
first_lst, second_lst = zip(*lst)
second_lst = list(second_lst)
second_lst.insert(0, second_lst.pop())
lst = list(zip(first_lst, second_lst))

And another option:

first, second = zip(*lst)
second = deque(second)
second.rotate()
lst = list(zip(first, second))

10 Comments

You mean was it wrong? I think it was downvoted when you only had the first solution. And I think that one doesn't scale well to the desired larger rotations, maybe someone didn't like that. But I love the deque one, so have my upvote :-)
@superbrain Thank you :-) I do think a buffer of rotations together with the first solution is more scalable tbh. I've upvoted your answer, but like my 2 other solutions, it causes copying of the data.
Not sure what you mean with buffer of rotations. But presumably it requires a bigger code rewrite than passing n to rotate :-)
Meh, that "highly memory-optimized" version takes O(n) extra space. I meant this, which only takes O(1) extra space.
Only two passes, really. The two partial passes together make one complete pass. But yes, it's probably slower. Only memory-optimized.
|
0

Rotate-by-n with O(1) extra space[*] using the old triple-reverse:

a = [(1, 1), (2, 2), (3, 3), (4, 4), (1, 5)]
n = 2

def reverse(start, stop):
    i, j = start, stop - 1
    while i < j:
        a[i], a[j] = (a[i][0], a[j][1]), (a[j][0], a[i][1])
        i += 1
        j -= 1
k = -n % len(a)
reverse(0, k)
reverse(k, len(a))
reverse(0, len(a))

print(a)

Output:

[(1, 4), (2, 5), (3, 1), (4, 2), (1, 3)]

[*]: Except when there are other references to the tuples, in which case they can't go to the free list and become reused.

Comments

0

You had a good start with collections.deque:

from collections import deque

f = [(1, 1), (2, 2), (3, 3), (4, 4), (1, 5)]

d = deque(map(lambda x, y: y, *zip(*f)))

d.rotate(1)

list(zip(map(lambda x, y: x, *zip(*f)), d))
[(1, 5), (2, 1), (3, 2), (4, 3), (1, 4)]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.