如果所有值(在该行或列中)为None,则从2D列表中删除行或列

时间:2009-12-31 04:16:14

标签: python list

我有一个网格(6行,5列):

grid = [
        [None, None, None, None, None],
        [None, None, None, None, None],
        [None, None, None, None, None],
        [None, None, None, None, None],
        [None, None, None, None, None],
        [None, None, None, None, None],
        ]

我增加了网格,它可能会变成:

grid = [
        [{"some" : "thing"}, None, None, None, None],
        [None, None, None, None, None],
        [None, None, None, None, None],
        [None, None, None, {"something" : "else"}, None],
        [None, {"another" : "thing"}, None, None, None],
        [None, None, None, None, None],
        ]

我想删除其中包含所有 None的整个行和列。所以在前面的代码中,网格将转换为:

grid = [
        [{"some" : "thing"}, None, None],
        [None, None, {"something" : "else"}],
        [None, {"another" : "thing"}, None],
        ]

我删除了第1,2,5行(零索引)和第2列和第4列。

我现在删除行的方式:

for row in range(6):
    if grid[row] == [None, None, None, None, None]:
        del grid[row] 

我还没有很好的方法来删除None列。这样做有“pythonic”的方法吗?

6 个答案:

答案 0 :(得分:7)

这不是最快的方式,但我认为这很容易理解:

def transpose(grid):
    return zip(*grid)

def removeBlankRows(grid):
    return [list(row) for row in grid if any(row)]

print removeBlankRows(transpose(removeBlankRows(transpose(grid))))

输出:

[[{'some': 'thing'}, None, None],
 [None, None, {'something': 'else'}],
 [None, {'another': 'thing'}, None]]

工作原理:我使用zip编写一个转换行和列的函数。第二个函数removeBlankRows删除所有元素都为None的行(或在布尔上下文中计算为false的任何元素)。然后执行整个操作我转置网格,删除空白行(这是原始数据中的列),再次转置,然后删除空行。

如果仅删除None而不是其他评估为false的内容很重要,请将removeBlankRows函数更改为:

def removeBlankRows(grid):
    return [list(row) for row in grid if any(x is not None for x in row)]

答案 1 :(得分:1)

grid = ...

# remove empty rows
grid = [x for x in grid if any(x)]
# if any value you put in won't evaluate to False
# e.g. an empty string or empty list wouldn't work here
# in that case, use:
grid = [x for x in grid if any(n is not None for n in x)]

# remove empty columns
if not grid:
  raise ValueError("empty grid")
  # or whatever, as next line assumes grid[0] exists
empties = range(len(grid[0])) # assume all empty at first
for r in grid:
  empties = [c for c in empties if r[c] is None] # strip out non-empty
if empties:
  empties.reverse() # apply in reversed order
  for r in grid:
    for c in empties:
      r.pop(c)

答案 2 :(得分:1)

使用zip()转置不规则阵列,再次运行清除例程,然后再次zip()

答案 3 :(得分:0)

如果你只有转置功能,你可以这样做:transpose(removeRows(transpose(removeRows(mat))))

实际上......使用位掩码是一个更好的主意。

让我考虑一下......

首先计算网格掩码:

grid_mask = [
10000,
00000,
00000,
00010,
00000
]

现在删除零:

grid_mask = [
10000,
00010,
]

现在和所有值按位:

grid_mask = 10010

现在删除除第1和第4列以外的所有列。

答案 4 :(得分:0)

这是快速尝试

它适用于任何大小的矩阵,行也可以是不同的大小,并且可能很快:)

from collections import defaultdict
grid = [
        [{"some" : "thing"}, None, None, None, None],
        [None, None, None, None, None],
        [None, None, None, None, None],
        [None, None, None, {"something" : "else"}, None],
        [None, {"another" : "thing"}, None, None, None],
        [None, None, None, None, None],
        ]

# go thru the grid remove, rows which have all None
# doing that count None in each columns, remove such columns later
newGrid = []
colSize = len(grid)
colCount = defaultdict(int)
for row in grid:
    allNone = True
    for c, cell in enumerate(row):
        if cell is None:
            colCount[c] += 1
        else:
            allNone = False

    if not allNone: # only add rows which are not all none
        newGrid.append(row)

# get cols which need to be removed
removeCols = [col for col, count in colCount.iteritems() if count == colSize]
removeCols.sort(reverse=True) 

# now go thru each column and remove all None Columns
for row in newGrid:
    for col in removeCols:
        row.pop(col)

grid = newGrid
import pprint
pprint.pprint(grid)

<强>输出:

[[{'some': 'thing'}, None, None],
 [None, None, {'something': 'else'}],
 [None, {'another': 'thing'}, None]]

答案 5 :(得分:0)

您还可以使用内置函数any(),它检查迭代的任何元素是否具有非None值。它比比较快,你不需要知道迭代的大小。

>>> def remove_rows( matrix ):
...    '''Returns a matrix without empty rows'''
...    ret_matrix = []
...    for row in matrix:
...        #Check if the row has any value or all are None
...        if any(row):
...            ret_matrix.append(row)
...
...    return ret_matrix
#You can do it also with a list comprehension, which will be even faster
>>> def remove_rows(matrix):
...     '''Returns a matrix without empty rows'''
...     ret_matrix = [ row for row in matrix if  any(row) ]
...     return ret_matrix

>>> grid = [
...         [{"some" : "thing"}, None, None, None, None],
...         [None, None, None, None, None],
...         [None, None, None, None, None],
...         [None, None, None, {"something" : "else"}, None],
...         [None, {"another" : "thing"}, None, None, None],
...         [None, None, None, None, None],
...         ]


>>> grid = remove_rows( grid )
>>> grid
[
 [{'some': 'thing'}, None, None, None, None], 
 [None, None, None, {'something': 'else'}, None], 
 [None, {'another': 'thing'}, None, None, None]
]

#transpose grid using zip (using asterisk)
>>> grid = zip(*grid)
#Note that zip returns tuples
>>> grid
[
  ({'some': 'thing'}, None, None), 
  (None, None, {'another': 'thing'}),
  (None, None, None), 
  (None, {'something': 'else'}, None), 
  (None, None, None)
]

>>> grid = remove_rows(grid)
>>> grid
[
  ({'some': 'thing'}, None, None), 
  (None, None, {'another': 'thing'}),
  (None, {'something': 'else'}, None)
]
>>> #Transpose again to get the first matrix, without empty rows or columns
>>> final_grid = zip(*grid)
>>> final_grid
[
 ({'some': 'thing'}, None, None),
 (None, None, {'something': 'else'}), 
 (None, {'another': 'thing'}, None)
]