4

i was trying a pattern in Python if n == 6

1 2 3 4 5
2 3 4 5 1
3 4 5 1 2
4 5 1 2 3
5 1 2 3 4

after trying to think a lot i did it like this --->

n = 6

for i in range(1,n):
    x = 1
    countj = 0
    for j in range(i,n):
        countj +=1
        print(j,end=" ")
        if j == n-1 and countj < n-1 :
            while countj < n-1:
                print(x , end =" ")
                countj +=1
                x +=1
        
    print()

but i don't think it is the best approach, I was trying to search some better approach , but not able to get the proper one, So that I came here,, is there any possible better approach for the problem?

AcK
  • 2,063
  • 2
  • 20
  • 27

4 Answers4

11

I would do like this, using a rotating deque instance:

>>> from collections import deque
>>> n = 6
>>> d = deque(range(1, n))
>>> for _ in range(1, n):
...     print(*d)
...     d.rotate(-1)
... 
1 2 3 4 5
2 3 4 5 1
3 4 5 1 2
4 5 1 2 3
5 1 2 3 4

There is a similar/shorter code possible just using range slicing, but maybe it's a bit harder to understand how it works:

>>> ns = range(1, 6)
>>> for i in ns:
...     print(*ns[i-1:], *ns[:i-1])
... 
1 2 3 4 5
2 3 4 5 1
3 4 5 1 2
4 5 1 2 3
5 1 2 3 4

You could also create a mathematical function of the coordinates, which might look something like this:

>>> for row in range(5):
...     for col in range(5):
...         print((row + col) % 5 + 1, end=" ")
...     print()
... 
1 2 3 4 5 
2 3 4 5 1 
3 4 5 1 2 
4 5 1 2 3 
5 1 2 3 4 

A too-clever way using list comprehension:

>>> r = range(5)
>>> [[1 + r[i - j - 1] for i in r] for j in reversed(r)]
[[1, 2, 3, 4, 5],
 [2, 3, 4, 5, 1],
 [3, 4, 5, 1, 2],
 [4, 5, 1, 2, 3],
 [5, 1, 2, 3, 4]]

more-itertools has this function:

>>> from more_itertools import circular_shifts
>>> circular_shifts(range(1, 6))
[(1, 2, 3, 4, 5),
 (2, 3, 4, 5, 1),
 (3, 4, 5, 1, 2),
 (4, 5, 1, 2, 3),
 (5, 1, 2, 3, 4)]
wim
  • 338,267
  • 99
  • 616
  • 750
1

You can use itertools.cycle to make the sequence generated from range repeat itself, and then use itertools.islice to slice the sequence according to the iteration count:

from itertools import cycle, islice
n = 6
for i in range(n - 1):
    print(*islice(cycle(range(1, n)), i, i + n - 1))

This outputs:

1 2 3 4 5
2 3 4 5 1
3 4 5 1 2
4 5 1 2 3
5 1 2 3 4
blhsing
  • 91,368
  • 6
  • 71
  • 106
1

Your 'pattern' is actually known as a Hankel matrix, commonly used in linear algebra.

So there's a scipy function for creating them.

from scipy.linalg import hankel
hankel([1, 2, 3, 4, 5], [5, 1, 2, 3, 4])

or

from scipy.linalg import hankel
import numpy as np

def my_hankel(n):
    x = np.arange(1, n)
    return hankel(x, np.roll(x, 1))

print(my_hankel(6))

Output:

[[1 2 3 4 5]
 [2 3 4 5 1]
 [3 4 5 1 2]
 [4 5 1 2 3]
 [5 1 2 3 4]]
Bill
  • 10,323
  • 10
  • 62
  • 85
  • 1
    Related: [Creating an identity Matrix containing diagonally determined values](https://stackoverflow.com/a/40496902/674039) – wim Sep 22 '21 at 04:53
  • Note that *all* Hankel matrices are symmetric, by definition. I’m not sure if there is a special name for this particular kind.. maybe a “Latin square” Hankel?? :) – wim Sep 22 '21 at 05:20
  • @wim Good point. I changed it’s name. – Bill Sep 22 '21 at 05:36
0

Seeing lots of answers involving Python libraries. If you want a simple way to do it, here it is.

n = 5
arr = [[1 + (start + i) % n for i in range(n)] for start in range(n)]
arr_str = "\n".join(" ".join(str(cell) for cell in row) for row in arr)
print(arr_str)
Modularizer
  • 611
  • 4
  • 8