У меня есть сетка (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
s в них. Таким образом в предыдущем коде, сетка была бы преобразована в:
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" способ сделать это?
Это не самый быстрый путь, но я думаю, что его довольно легко понять:
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)]
Также можно использовать встроенную функцию 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)
]
Используйте zip()
для транспонирования поврежденного массива, повторите процедуру очистки, затем zip()
снова.
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)
Если бы у вас была функция транспонирования, вы могли бы сделать: transpose(removeRows(transpose(removeRows(mat))))
На самом деле ... использование битовой маски - лучшая идея.
Дайте мне подумать об этом ...
Сначала вычислите маску сетки:
grid_mask = [
10000,
00000,
00000,
00010,
00000
]
Теперь удалите нули:
grid_mask = [
10000,
00010,
]
Теперь и все значения по битам:
grid_mask = 10010
Теперь удалите все, кроме 1-го и 4-го столбцов.
*.Вот быстрая попытка
Это сработает для любой матрицы размеров, и строки тоже могут быть разного размера, и может быть быстрым :)
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]]