Как уже упоминалось, вы не можете сделать это без цикла.Однако, используя встроенные функции, вот функциональный подход, который не использует явно какой-либо цикл:
In [24]: from operator import itemgetter
In [25]: def remove_col(arr, ith):
...: itg = itemgetter(*filter((ith).__ne__, range(len(arr[0]))))
...: return list(map(list, map(itg, arr)))
...:
Демонстрация:
In [26]: remove_col(A, 1)
Out[26]: [[1, 3, 4], ['a', 'c', 'd'], [12, 14, 15]]
In [27]: remove_col(A, 3)
Out[27]: [[1, 2, 3], ['a', 'b', 'c'], [12, 13, 14]]
Обратите внимание, что вместо list(map(list, map(itg, arr)))
, если вы толькоreturn map(itg, arr)
даст ожидаемый результат, но в качестве итератора итераторов вместо списка списков.В этом случае это будет более оптимизированный подход с точки зрения как памяти, так и времени выполнения.
Также, используя циклы, я бы сделал следующее:
In [31]: def remove_col(arr, ith):
...: return [[j for i,j in enumerate(sub) if i != ith] for sub in arr]
Удивительно (нет, если вы верите в силу C :)) для больших массивов функциональный подход еще быстрее.
In [41]: arr = A * 10000
In [42]: %timeit remove_col_functional(arr, 2)
8.42 ms ± 37.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [43]: %timeit remove_col_list_com(arr, 2)
23.7 ms ± 165 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
# And if in functional approach you just return map(itg, arr)
In [47]: %timeit remove_col_functional_iterator(arr, 2)
1.48 µs ± 4.71 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)