разбить список на несколько переменных в Matlab - PullRequest
5 голосов
/ 22 декабря 2011

Если у меня есть короткий список (скажем, два или три элемента), я бы хотел иметь функцию, которая разделяет его на несколько переменных. Примерно так:

li=[42 43];
[a b]=split(li)
 --> a=42
 --> b=43

Я ищу способ сделать мой код короче в Matlab. Это было бы хорошо в некоторых ситуациях. Например:

positions=zeros(10,3);
positions= [....];
[x y z]=split(max(positions,1))

вместо того, чтобы делать:

pos=max(positions,1)
x=pos(1);
y=pos(2);
z=pos(3);

Ответы [ 3 ]

5 голосов
/ 22 декабря 2011

Единственный известный мне способ сделать это - использовать deal.Однако это работает только с массивами ячеек или с явными аргументами в deal.Поэтому, если вы хотите иметь дело с матрицами / векторами, вы должны сначала преобразовать в массив ячеек num2cell / mat2cell.Например:

% multiple inputs
[a b]   = deal(42,43) % a=2, b=3
[x y z] = deal( zeros(10,1), zeros(10,1), zeros(10,1) )

% vector input
li  = [42 43];
lic = num2cell(li);
[a b]=deal(lic{:}) % unforunately can't do num2cell(li){:}
% a=42, b=43

% matrix input
positions  = zeros(10,3);
% create cell array, one column each
positionsc = mat2cell(positions,10,[1 1 1]);
[x y z]    = deal(positionsc{:})

Первая форма хороша (deal(x,y,...)), поскольку она не требует явного создания массива ячеек.

В противном случае я считаю, что не стоит использовать deal когда вам нужно преобразовать свои матрицы в массивы ячеек только для того, чтобы снова преобразовать их: просто сохраните накладные расходы.В любом случае все равно требуется 3 строки: сначала для определения матрицы (например, li), затем для преобразования в ячейку (lic), затем для выполнения deal (deal(lic{:})).

Если вы действительно хотели уменьшить количество строк, есть решение в этом вопросе , где вы просто создаете свою собственную функцию, которая повторяется здесь, и модифицируется так, что вы можете определить ось для разделения:

function varargout = split(x,axis)
% return matrix elements as separate output arguments
% optionally can specify an axis to split along (1-based).
% example: [a1,a2,a3,a4] = split(1:4)
% example: [x,y,z] = split(zeros(10,3),2)
if nargin < 2
    axis = 2; % split along cols by default
end
dims=num2cell(size(x));
dims{axis}=ones([1 dims{axis}]);
    varargout = mat2cell(x,dims{:});
end

Затем используйте вот так:

[a b]  = split([41 42])
[x y z]= split(zeros(10,3), 2) % each is a 10x1 vector
[d e]  = split(zeros(2,5), 1)  % each is a 1x5 vector

Это все же делает матрица -> ячейка -> матрица вещь, хотя.Если ваши векторы малы, и вы не делаете это в цикле миллион раз, все будет в порядке.

4 голосов
/ 22 декабря 2011

Вы можете извлечь значения в списке в различные переменные с помощью

li = [42 43 44];
tmp = num2cell(li);
[a b c] = deal(tmp{:})

a =
    42
b =
    43
c =
    44
2 голосов
/ 18 декабря 2014

Вы можете управлять этим в одном выражении, если вы действительно хотите:

a = [1, 2, 3, 4]
[b, c, d, e]=feval(@(x)x{:}, num2cell(a))

Результат:

b =
     1
c =
     2
d =
     3
e =
     4

Если вы хотите много использовать это, вы можете быстро сделать анонимную функцию:

expand = @(A) feval(@(x)x{:}, num2cell(A))
[b, c, d, e]=expand(a)

Я считаю, что это сработает со всем, что примет num2cell, который даже не должен быть числовым, просто должен быть массивом, которым почти все в Matlab является.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...