Нарезка на python, похожая на MATLAB

#python #matlab #list #slice

#python #matlab #Список #нарезка

Вопрос:

В Matlab срез может быть вектором:

 a = {'a','b','c','d','e','f','g'}; % cell array
b = a([1:3,5,7]);
  

Как я могу сделать то же самое в python?

 a = ['a','b','c','d','e','f','g']
b = [a[i] for i in [0,1,2,4,6]]
  

но когда 1: 3 становится 1: 100, это не сработает. Использование range(2),4,6 возвращает ([0,1,2],4,6), нет (0,1,2,4,6). Существует ли быстрый и «питонический» способ?

Ответ №1:

Если вы хотите делать вещи, похожие на Matlab в Python, NumPy всегда должен быть вашим первым предположением. В этом случае вам нужно numpy.r_ :

 from numpy import array, r_
a = array(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])
print a[r_[1:3, 5, 7]]

['b' 'c' 'f' 'h']
  

Комментарии:

1. , хороший, понятия не имел о r_

2. Обратите внимание, что r_[:3, 5:] возвращает [0, 1, 2, 0, 1, 2, 3, 4] , поскольку он не знает о . Обходным путем является использование, r_[:3, 5:len(a)] которое возвращает [0, 1, 2, 5, 6, 7] . тем не менее, это самое близкое, что вы найдете к нарезке типа Matlab.

Ответ №2:

Одним из способов является использование itertools.chain :

 >>> b = [a[i] for i in itertools.chain(range(2), [5, 6])]
>>> b
['b', 'c', 'f', 'g']
  

Примечания:

  1. Диапазоны адаптированы из Matlab (индексация на основе 1) в Python (индексация на основе 0)
  2. Вы можете выиграть, изменив range на xrange , если у вас Python 2.x, чтобы избежать создания всего списка диапазонов на лету. Я не думаю, что это сильно повлияет на производительность, но об этом приятно знать.

Ответ №3:

Попробуйте

 [a[i] for i in range(2)   [4, 6]]
  

Если вы используете NumPy, то у вас есть еще несколько вариантов:

 import numpy as N
a = N.array(['a', 'b', 'c', 'd', 'e', 'f', 'g'])
b = a[range(2)   [4, 6]]
c = a.take(range(2)   [4, 6])
  

Комментарии:

1. Однако при этом список будет скопирован. Расточительно с большими диапазонами. Используйте itertools.chain , чтобы избежать этого.