Удалите строку или столбец из 2D списка, если все значения (в той строке или столбце) не являются Ни одним

У меня есть сетка (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],
        ]

Я хочу удалить все строки и столбцы, которые имеют все Nones в них. Таким образом в предыдущем коде, сетка была бы преобразована в:

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" способ сделать это?

5
задан Matt 31 December 2009 в 04:26
поделиться

6 ответов

Это не самый быстрый путь, но я думаю, что его довольно легко понять:

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 (или что-либо, что в булевом контексте оценивается как ложное). Затем для выполнения всей операции я переставляю сетку, удаляю пустые строки (которые являются столбцами в исходных данных), переставляю заново, затем удаляю пустые строки.

Если важно только удалить None, а не другие вещи, которые оцениваются как ложные, измените функцию removeBlankRows на:

def removeBlankRows(grid):
    return [list(row) for row in grid if any(x is not None for x in row)]
7
ответ дан 14 December 2019 в 01:09
поделиться

Также можно использовать встроенную функцию 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)
]
0
ответ дан 14 December 2019 в 01:09
поделиться

Используйте zip() для транспонирования поврежденного массива, повторите процедуру очистки, затем zip() снова.

.
1
ответ дан 14 December 2019 в 01:09
поделиться
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)
1
ответ дан 14 December 2019 в 01:09
поделиться

Если бы у вас была функция транспонирования, вы могли бы сделать: transpose(removeRows(transpose(removeRows(mat))))

На самом деле ... использование битовой маски - лучшая идея.

Дайте мне подумать об этом ...

Сначала вычислите маску сетки:

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

Теперь удалите нули:

grid_mask = [
10000,
00010,
]

Теперь и все значения по битам:

grid_mask = 10010

Теперь удалите все, кроме 1-го и 4-го столбцов.

*.
0
ответ дан 14 December 2019 в 01:09
поделиться

Вот быстрая попытка

Это сработает для любой матрицы размеров, и строки тоже могут быть разного размера, и может быть быстрым :)

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]]
0
ответ дан 14 December 2019 в 01:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: