简体   繁体   中英

Unexpected result with Python reversed()

I have the following code:

n = int(input('n: '))
[print(' '.join(list(reversed([str(j) for j in range(i * n + n, i * n, -1)])))) if i % 2 == 1 else print(' '.join([str(j) for j in range(i * n + 1, i * n + n + 1)])) for i in range(n)]

Expected results:

n: 5
1 2 3 4 5
10 9 8 7 6
11 12 13 14 15
20 19 18 17 16
21 22 23 24 25

Actual result:

n: 5
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25

Why doesn't reversed() work here, and what do I need to fix to match the expected result?

Your parameters to range() already reverse the values -- what you're doing amounts to performing a reverse operation twice.

You shouldn't really be using a list comprehension for side effects, but to resolve your immediate issue, remove reversed() :

n = int(input('n: '))
[print(' '.join(list([str(j) for j in range(i * n + n, i * n, -1)]))) if i % 2 == 1 else print(' '.join([str(j) for j in range(i * n + 1, i * n + n + 1)])) for i in range(n)]

And for completeness, here is a version of your code that does not make use of a list comprehension:

n = int(input('n: '))

for i in range(n):
    elements = list(map(str, range(i * n + 1, (i + 1) * n + 1)))
    if i % 2 == 0:
        print(' '.join(elements))
    else:
        print(' '.join(reversed(elements)))

These output:

1 2 3 4 5
10 9 8 7 6
11 12 13 14 15
20 19 18 17 16
21 22 23 24 25

I think the issue is that your range had a -1 increment which in turn was reversed by the reverse() call. So, if we take the reverse() out, we get the desired results:

n = int(input('n: '))
[ print(' '.join(list([str(j) for j in range(i * n + n, i * n,-1)]))) if i % 2 == 1 else print(' '.join([str(j) for j in range(i * n + 1, i * n + n + 1)])) for i in range(n) ] 

With these results:

n: 5
1 2 3 4 5
10 9 8 7 6
11 12 13 14 15
20 19 18 17 16
21 22 23 24 25

Alternatively, you can remove the -1 increment from your range() statement. You'll also need to change the start and end of the range accordingly. Once we change the range from range(i * n + n, i * n,-1) to range(i * n + 1 , i * n + n + 1) , we get this code (and the same results:

n = int(input('n: '))
[print(' '.join(list(reversed([str(j) for j in range(i * n + 1 , i * n + n + 1)])))) if i % 2 == 1 else print(' '.join([str(j) for j in range(i * n + 1, i * n + n + 1)])) for i in range(n)]

Should you wish to continue using a single list comprehension, it pairs well with a conditional expression to either reverse the iterator or not and then convert to a list.

The second clause in the comprehension that introduces r is a list with only one element. This allows us to not have to recalculate r twice.

[list(r if i % 2 == 0 else reversed(r))
  for i in range(n) 
  for r in [range(i * n + 1, i * n + 1 + n)]]

For n being 5 this will yield:

[[1, 2, 3, 4, 5], [10, 9, 8, 7, 6], [11, 12, 13, 14, 15], [20, 19, 18, 17, 16], [21, 22, 23, 24, 25]]

We can then generate a list of strings.

[' '.join(map(str, (r if i % 2 == 0 else reversed(r))))
  for i in range(n) 
  for r in [range(i * n + 1, i * n + 1 + n)]]

Yields:

['1 2 3 4 5', '10 9 8 7 6', '11 12 13 14 15', '20 19 18 17 16', '21 22 23 24 25']

And then we join those with newlines. The list comprehension is now unnecessary, and we can pass a generator expression to str.join .

'\n'.join(' '.join(map(str, (r if i % 2 == 0 else reversed(r))))
  for i in range(n) 
  for r in [range(i * n + 1, i * n + 1 + n)])

We get:

'1 2 3 4 5\n10 9 8 7 6\n11 12 13 14 15\n20 19 18 17 16\n21 22 23 24 25'

Then you just have to print that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM