Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I change the location of columns without using pandas

I have a matrix as shown below;

matrix="""  8 1 A A A A 8
            8 5 A A A 3 8
            7 2 A A 1 4 7
            6 1 3 A 2 5 7
            2 4 5 A 1 1 1"""

And here's my code block:

lines= [i.strip().split() for i in matrix.splitlines()]
lst=[[lines[i][j] for i in range(len(lines))]for j in range(len(lines[0]))]
h=0
while h<=len(lines[0]):
    for i in range(len(lines[0])-1,0,-1):
        for j in range(len(lines)-1,-1,-1):
            for k in lst:
                if k.count('A')==len(lines):
                    if lines[j][i-1]=='A':
                        lines[j][i-1]=lines[j][i]
                        lines[j][i]='A'
    h+=1
for line in lines:
    print(*(i or " " for i in line) , sep=" ")

If a column full of A's, I want to move that column to the most right side, but my code moves all A's to right. This is my output:

8 1 8 A A A A
8 5 3 8 A A A
7 2 1 4 7 A A
6 1 3 2 5 7 A
2 4 5 1 1 1 A

I want a output something like that:

8 1 A A A 8 A
8 5 A A 3 8 A
7 2 A 1 4 7 A
6 1 3 2 5 7 A
2 4 5 1 1 1 A 
like image 544
Stewie Avatar asked Dec 13 '22 13:12

Stewie


2 Answers

You can use zip() to transpose the matrix, sort all that are pure "A" to its end and reverse-transpose with zip() again:

matrix="""  8 1 A A A A 8
            8 5 A A A 3 8
            7 2 A A 1 4 7
            6 1 3 A 2 5 7
            2 4 5 A 1 1 1"""

# string to list of lists of strings
m = [[x.strip() for x in line.split()] for line in matrix.split("\n")]
print(*m,sep="\n")

# transpose and sort
t_m = [list(line) for line in zip(*m)]
t_m.sort(key = lambda x: all(k=="A" for k in x))

# reverse transpose
m = [list(line) for line in zip(*t_m)]
print(*m,sep="\n")

Output:

# before
['8', '1', 'A', 'A', 'A', 'A', '8']
['8', '5', 'A', 'A', 'A', '3', '8']
['7', '2', 'A', 'A', '1', '4', '7']
['6', '1', '3', 'A', '2', '5', '7']
['2', '4', '5', 'A', '1', '1', '1']

# after
['8', '1', 'A', 'A', 'A', '8', 'A']
['8', '5', 'A', 'A', '3', '8', 'A']
['7', '2', 'A', '1', '4', '7', 'A']
['6', '1', '3', '2', '5', '7', 'A']
['2', '4', '5', '1', '1', '1', 'A']

The transposed data looks like this:

# before sorting
['8', '8', '7', '6', '2']
['1', '5', '2', '1', '4']
['A', 'A', 'A', '3', '5']
['A', 'A', 'A', 'A', 'A']  # this is the column you want to sort behind all others
['A', 'A', '1', '2', '1']
['A', '3', '4', '5', '1']
['8', '8', '7', '7', '1']

# after sort
['8', '8', '7', '6', '2']
['1', '5', '2', '1', '4']
['A', 'A', 'A', '3', '5']
['A', 'A', '1', '2', '1']
['A', '3', '4', '5', '1']
['8', '8', '7', '7', '1']
['A', 'A', 'A', 'A', 'A']  # now it is here

The sort/sorting works because it is only True if the whole row consists of 'A' (True == 1) all others are False == 0.

Sorting is stable so it does not change the relative orders between rows that evaluate False.

like image 133
Patrick Artner Avatar answered Dec 22 '22 17:12

Patrick Artner


Here's a way using numpy:

s = np.array([x.strip() for x in matrix.split()]).reshape(5,7)
print(s)

array[['8', '1', 'A', 'A', 'A', 'A', '8'],
     ['8', '5', 'A', 'A', 'A', '3', '8'],
     ['7', '2', 'A', 'A', '1', '4', '7'],
     ['6', '1', '3', 'A', '2', '5', '7'],
     ['2', '4', '5', 'A', '1', '1', '1']]

You could use np.flatnonzero to locate columns where all values are 0, and swap them with the last:

m = np.flatnonzero((s == 'A').all(axis=0))[0]
s.T[[m, s.shape[1]-1]] = s.T[[s.shape[1]-1, m]]

array([['8', '1', 'A', '8', 'A', 'A', 'A'],
       ['8', '5', 'A', '8', 'A', '3', 'A'],
       ['7', '2', 'A', '7', '1', '4', 'A'],
       ['6', '1', '3', '7', '2', '5', 'A'],
       ['2', '4', '5', '1', '1', '1', 'A']], dtype='<U21')
like image 39
yatu Avatar answered Dec 22 '22 16:12

yatu