【问题标题】:How can I change the location of columns without using pandas如何在不使用熊猫的情况下更改列的位置
【发布时间】:2018-12-28 10:53:19
【问题描述】:

我有一个矩阵如下图;

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"""

这是我的代码块:

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=" ")

如果一列全是 A,我想将该列移到最右侧,但我的代码将所有 A 移到右侧。这是我的输出:

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

我想要这样的输出:

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 

【问题讨论】:

    标签: python arrays python-3.x matrix


    【解决方案1】:

    您可以use zip() 转置矩阵,将所有纯"A" 排序到最后并再次使用zip() 进行反向转置:

    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")
    

    输出:

    # 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']
    

    转置后的数据如下所示:

    # 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
    

    sort/sorting 有效,因为如果整行由 'A' (True == 1) 组成,则它只是 True,所有其他都是 False == 0

    排序是稳定的,因此它不会改变评估False 的行之间的相对顺序。

    【讨论】:

    • 最好将转置提取到单独的效用函数中
    • @AzatIbrakov 好点 - 如果您多次使用它,您应该这样做。虽然它是一个 1-liner,但为简洁起见,我保持原样。
    • @PatrickArtner 非常感谢您的代码适用于我的所有输入文件。
    【解决方案2】:

    这是一种使用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']]
    

    您可以使用np.flatnonzero 定位all 值为0 的列,并将它们与最后一个交换:

    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')
    

    【讨论】:

    • import numpy as np - 这不是 pandas ......但它是另一个导入 ;) 不错的一个虽然
    【解决方案3】:

    首先,让我们定义用于转置列表列表的实用函数

    def transpose(elements):
        return list(map(list, zip(*elements)))
    

    那么让我们按照规则定义排序键:如果列表元素等于'A',那么它排在最后,否则保持在原来的位置

    def sorting_key(indexed_row):
        return all(element == 'A' for element in indexed_row[1]), indexed_row
    

    之后我们的解决方案将是

    >>> from operator import itemgetter
    >>> transpose(map(itemgetter(1), sorted(enumerate(transpose(lines)),
                                            key=sorting_key)))
    

    这给了我们

    [['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']]
    

    或者正如@PatrickArtner 指出的那样,sorted 使用Timsort,即stable algorithm,所以我们不需要处理将非全“A”列留在原来的位置并定义的情况:

    def sorting_key(row):
        return all(element == 'A' for element in row)
    

    之后我们可以简单地写

    >>> transpose(sorted(transpose(lines),
                         key=sorting_key))
    

    【讨论】:

      猜你喜欢
      • 2019-03-01
      • 2013-11-19
      • 1970-01-01
      • 2018-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-21
      • 1970-01-01
      相关资源
      最近更新 更多