gpt4 book ai didi

function - 如何将任意数据类型写入 Matlab 元胞数组

转载 作者:行者123 更新时间:2023-12-02 22:37:41 25 4
gpt4 key购买 nike

这是一个一般性问题,与特定操作无关。我希望能够将任意函数的结果写入元胞数组的元素,而不考虑函数返回的数据类型。考虑这个伪代码:

zout = cell(n,m);
myfunc = str2func('inputname'); %assume myfunc puts out m values to match zout dimensions
zout(1,:) = myfunc(x,y);

例如,假设 xy 是具有适当维度的字符串或字符串单元格,这将适用于 "inputname"== "strcat"。但是如果 "inputname"== "strcmp"那么输出是一个逻辑数组,Matlab 会抛出一个错误。我需要做

zout(1,:) = num2cell(strcmp(x,y));

所以我的问题是:有没有一种方法可以填充单元格数组 zout 而不必测试 myfunc(x,y 生成的变量类型?应该我首先使用的是 struct(如果是这样,填充它的最佳方式是什么)?
(我通常是 R 用户,我可以毫无痛苦地使用 list 变量)

编辑:为简化整体范围,添加以下“要求”:现在让我们假设,对于返回多个输出的函数,只有第一个需要在 zout 中捕获。但是,当此输出是 N 个值的向量或单元格的向量(即 Nx1 元胞数组)时,这些 N 个值将映射到 zout(1,1:N)

最佳答案

So my question is: is there a way to fill the cell array zout without having to test for the type of variable generated by myfunc(x,y) ? Should I be using a struct in the first place (and if so, what's the best way to populate it)?

@NotBoStyf 提供的答案几乎已经有了,但还不完全是。元胞阵列是正确的方法。然而,答案在很大程度上取决于函数的输出数量。

只有一个输出的函数

strcmp 函数只有一个输出,即一个数组。原因是

zout{1,:} = strcmp(x,y)

给你一条错误消息,当 zout 的尺寸为 N x 2 时,左侧 (zout{1,:}) 需要来自右侧的两个输出。您可以通过以下方式解决此问题:

[zout{1,:}] = num2cell(strcmp(x,y));  % notice the square brackets on the LHS

但是,确实没有理由这样做。您可以简单地将 zout 定义为 N x 1 元胞数组并捕获结果:

zout = cell(1,1);

x = 'a';
y = { 'a', 'b' };

zout{1} = strcmp(x,y);

% Referring to the results:
x_is_y_1 = zout{1}(1);
x_is_y_2 = zout{1}(2);

还有一种情况需要考虑...

具有多个输出的函数

如果您的函数产生多个输出(与作为数组的单个输出相反),那么这将仅捕获第一个输出。产生多个输出的函数定义如下:

function [outA,outB] = do_something( a, b )
outA = a + 1;
outB = b + 2;
end

在这里,您需要显式捕获两个输出参数。否则,您只会得到 a。例如:

outA = do_something( [1,2,3], [4,5,6] ); % outA is [2,3,4]

[outA,outB] = do_something( [1,2,3], [4,5,6] ); % outA is [2,3,4], outB is [6,7,8]

Z1 = cell(1,1);
Z1{1,1} = do_something( [1,2,3], [4,5,6] ); % Z1{1,1} is [2,3,4]

Z2 = cell(1,2);
Z2{1,1:2} = do_something( [1,2,3], [4,5,6] ); % Same error as above.
% NB: You really never want to have a cell expansion that is not surrounded
% by square brackets.

% Do this instead:
[Z2{1,1:2}] = do_something( [1,2,3], [4,5,6] ); % Z2{1,1} is [2,3,4], Z2{1,2} is [6,7,8]

这也可以通过编程方式完成,但有一些限制。假设我们得到了函数func 接受一个输入并返回一个恒定(但未知)数量的输出。我们有包含我们要处理的输入的单元格数组 inp,我们想在 outp 周围的单元格中收集结果:

N = numel(inp);
M = nargout(@func); % number of outputs produced by func
outp = cell(N,M);
for i=1:N
[ outp{i,:} ] = func( inp{i} );
end

这种方法有一些注意事项:

  1. 它捕获所有 的输出。这并不总是您想要的。

  2. 捕获所有输出通常可以改变函数的行为。例如,find 函数在仅使用一个输出时返回线性索引,在使用两个输出时返回行/列索引,在使用三个输出时返回行/列/值。

  3. 它不适用于输出数量可变的函数。这些函数定义为 function [a,b,...,varargout] = func( ... )。如果函数在其输出列表中声明了 varargoutnargout 将返回一个负数,因为 Matlab 无法知道将产生多少输出。

将数组和单元格输出解包到单元格中

All true so far, but: what I am hoping for is a generic solution. I can't use num2cell if the function produces cell outputs. So what worked for strcmp will fail for strcat and vice versa. Let's assume for now that, for a function which returns multiple outputs, only the first one need be captured in zout – Carl Witthoft

要为返回单元格或数组的所有函数提供统一的输出语法,请使用适配器函数。下面是一个处理数字数组和单元格的示例:

function [cellOut] = cellify(input)
if iscell(input)
cellOut = input;
elseif isnumeric(input)
cellOut = num2cell(input);
else
error('cellify currently does not support structs or objects');
end
end

要将输出解压缩为二维元胞数组,每个输出的大小必须保持不变。假设 M 输出:

N = numel(inp);
% M is known and constant
outp = cell(N,M);
for i=1:N
outp(i,:) = cellify( func( inp{i} ) ); % NB: parentheses instead of curlies on LHS
end

然后可以将输出寻址为 outp{i,j}。另一种方法允许输出大小不同:

N = numel(inp);
% M is not necessary here
outp = cell(N,1);
for i=1:N
outp{i} = cellify( func( inp{i} ) ); % NB: back to curlies on LHS
end

然后可以将输出寻址为 outp{i}{j},并且输出的大小可以变化。

需要注意的几点:

  1. Matlab 单元基本上是低效的指针。 JIT 编译器并不总是像优化数值数组那样优化它们。

  2. 将数值数组拆分为单元格可能会占用相当多的内存。每个拆分值实际上是一个数字数组,它具有与其关联的大小和类型信息。在数值数组形式中,每个数组都会出现一次。当拆分数组时,每个元素都会发生一次。

关于function - 如何将任意数据类型写入 Matlab 元胞数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11209158/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com