如何在MATLAB中进行多重赋值?

48

这是我在寻找的一个例子:

>> foo = [88, 12];
>> [x, y] = foo;

之后,我会期望出现这样的内容:

>> x

x =

    88

>> y

y =

    12

但是我得到的错误信息类似于:

??? Too many output arguments.

我以为deal()可以做到,但它似乎只适用于单元格。

>> [x, y] = deal(foo{:});
??? Cell contents reference from a non-cell array object.

我该如何解决我的问题?如果我想分别处理它们,是否必须不断地以1和2作为索引?


3
只有当foo是一个单元格时才会生效。你将foo定义为一个标准数组,所以你收到了“??? Cell contents reference from a non-cell array object.”错误消息。请注意修改foo的类型为单元格。 - Justin Peel
9个回答

46

对于Matlab 7.0或更高版本来说,你根本不需要使用deal函数(编辑:对于 Matlab 7.0 或更新版本),而且对于你的例子,你也不需要使用mat2cell函数;你可以使用num2cell函数,而且不需要其他参数:

foo = [88, 12];
fooCell = num2cell(foo);
[x y]=fooCell{:}

x =

    88


y =

    12
如果您想出于其他原因使用 deal,您可以:
foo = [88, 12];
fooCell = num2cell(foo);
[x y]=deal(fooCell{:})

x =

    88


y =

    12

3
顺便提一下,在Matlab 7+中,我认为你只能在第一个例子中摆脱不使用deal函数。 - Justin Peel
有趣。我不知道现在deal是不必要的。然而,我故意使用mat2cell,因为我假设OP可能想要将列彼此分开。 - Jonas
3
这真的很好。但有没有办法让它都在一行上?也许可以这样写:[x y] = num2cell(foo){:}(抱歉,我对Matlab仍然经常感到困惑)。 - Benjamin Oakes
@Justin:说得好,你需要7.0(2004)或更高版本。@Jonas:没错,如果你想以不同的方式拆分,mat2cell是个好方法。@Benjamin:除非你一开始就使用单元格,否则我不知道有没有一行代码的方法;如果你从标量开始,可以使用deal(88,12)。如果我们能像许多Matlab命令那样使用num2cell(foo){:}这样的东西就好了。 - Ramashalanka

19
请注意deal只接受“list”作为参数,而不是单元数组。因此,以下内容按预期工作:
> [x,y] = deal(88,12)
x = 88

y = 12

c{:}语法将一个单元数组转换为列表,而列表是逗号分隔值,例如函数参数。这意味着您可以将c {:}语法用作除deal之外的其他函数的参数。要查看这一点,请尝试以下操作:

> z = plus(1,2)
z = 3

> c = {1,2};
> z = plus(c{:});
z = 3

8
为了在一行中使用num2cell解决方案,定义一个助手函数list:
function varargout = list(x)
% return matrix elements as separate output arguments
% example: [a1,a2,a3,a4] = list(1:4)

varargout = num2cell(x);

end

例子 [a1,a2,a3,a4] = list(1:4) 不会导致 Too many output arguments 错误吗? - zhangxaochen

4

就像mtrw所说的那样。基本上,你想要使用一个单元数组(虽然deal(88,12)也可以)。

假设你从一个n-by-2的数组foo开始,你想要将第一列赋值给x,第二列赋值给y,你需要执行以下操作:

foo = [88,12;89,13;90,14];
%# divide the columns of foo into separate cells, i.e. do mat2cell(foo,3,[1,1])
fooCell = mat2cell(foo,size(foo,1),ones(size(foo,2),1));
[x,y] = deal(fooCell{:});

3

DEAL非常有用,但同时也非常令人困惑。我相信foo本身需要是一个单元数组。以下代码在Octave中似乎有效,如果我记得正确的话,在MATLAB中也会有效:

> foo = {88, 12}
foo =

{
  [1,1] =  88
  [1,2] =  12
}

> [x,y] = deal(foo{:})
x =  88
y =  12

1

我不能评论其他答案,所以需要单独添加。

如果您从标量开始,可以使用deal(88,12)

deal也可用于非标量的一行代码,在这种情况下,当然前提是您已将它们存储在单独的变量中,例如:

a = 123;
b = rand(3);
c = {a, b};
d = struct('field','val')

现在你可以用一行代码处理它们:

>> [x,y,z,w] = deal(a,b,c,d)
x =
   123
y =
    0.6370    0.2165    0.6711
    0.2945    0.8803    0.2705
    0.7633    0.1537    0.0767
z = 
    [123]    [3x3 double]
w = 
    field: 'val'

然而,如果它们被打包在一个变量中,你只能在单元数组或结构体数组中使用deal(X{:})(对于单元数组)和deal(S.field)(对于结构体数组)进行处理。 (在后一种情况下,只处理一个字段,但从数组中的所有结构体中处理。)使用Matlab v.7+,你可以在其他答案中提到的情况下使用X {:}和S.field,无需使用deal

1
创建一个名为arr2vars的函数,以方便使用。
function varargout = arr2vars(arr)
% Distribute elements over variables

N = numel(arr);
if nargout ~= N
    error('Number of outputs does not match number of elements')
end
for k = 1:N
    varargout{k} = arr(k);
end

您可以像这样使用它:

[~,roi] = imcrop(im);
[x,w,y,h] = arr2vars(roi);

0

你可能在寻找

>>> foo = [88, 12];
>>> [x, y] = deal(foo(1), foo(2))

结果导致
x = 
    88

y = 
    12

所以你有一个工作的单行代码。


-1

有一种更简单的方法。

x = foo (1, 1)  
y = foo (1, 2)

提供

>> x

x =

88

>> y

y =

12

完整文档请参考Mathworks.


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接