我有一个变量 pth
,它是维度为 1xn
的元胞数组,其中 n
是用户输入。 pth
中的每个元素本身都是元胞数组,length(pth{k})
for k=1:n
是可变的(结果另一个功能)。每个元素 pth{k}{kk}
其中 k=1:n
和 kk=1:length(pth{k})
是一个整数的一维向量/再次可变长度的节点号。因此,总而言之,我有可变数量的可变长度向量,它们组织在可变数量的元胞数组中。
当您从 pth{1}
, pth{2}
, {pth 中随机选取一个向量时,我想尝试找到所有可能的交叉点{3}
等...文件交换上有各种功能似乎可以做到这一点,例如 this one或 this one .我遇到的问题是您需要以这种方式调用该函数:
mintersect(v1,v2,v3,...)
而且我不能在一般情况下写出所有输入,因为我不知 Prop 体有多少(这将是上面的 n
)。理想情况下,我想做这样的事情;
mintersect(pth{1}{1},pth{2}{1},pth{3}{1},...,pth{n}{1})
mintersect(pth{1}{1},pth{2}{2},pth{3}{1},...,pth{n}{1})
mintersect(pth{1}{1},pth{2}{3},pth{3}{1},...,pth{n}{1})
etc...
mintersect(pth{1}{1},pth{2}{length(pth{2})},pth{3}{1},...,pth{n}{1})
mintersect(pth{1}{1},pth{2}{1},pth{3}{2},...,pth{n}{1})
etc...
继续尝试所有可能的组合,但我无法用代码编写。这function来自 File Exchange 看起来是找到所有可能组合的好方法,但我再次遇到具有可变输入数量的函数调用的相同问题:
allcomb(1:length(pth{1}),1:length(pth{2}),...,1:length(pth{n}))
当您无法物理指定所有输入参数(因为输入参数的数量是可变的)时,有人知道如何解决输入参数数量可变的函数调用问题吗?这同样适用于 MATLAB 和 Octave,因此有两个标签。关于从每个 pth{k}
中随机获取向量时如何找到所有可能的组合/交叉点的任何其他建议欢迎!
编辑 2020 年 5 月 27 日
感谢疯狂物理学家的回答,我最终使用了以下有效的方法:
disp('Computing intersections for all possible paths...')
grids = cellfun(@(x) 1:numel(x), pth, 'UniformOutput', false);
idx = cell(1, numel(pth));
[idx{:}] = ndgrid(grids{:});
idx = cellfun(@(x) x(:), idx, 'UniformOutput', false);
idx = cat(2, idx{:});
valid_comb = [];
k = 1;
for ii = idx'
indices = reshape(num2cell(ii), size(pth));
selection = cellfun(@(p,k) p{k}, pth, indices, 'UniformOutput', false);
if my_intersect(selection{:})
valid_comb = [valid_comb k];
endif
k = k+1;
end
我自己的版本类似,但使用 for
循环而不是逗号分隔列表:
disp('Computing intersections for all possible paths...')
grids = cellfun(@(x) 1:numel(x), pth, 'UniformOutput', false);
idx = cell(1, numel(pth));
[idx{:}] = ndgrid(grids{:});
idx = cellfun(@(x) x(:), idx, 'UniformOutput', false);
idx = cat(2, idx{:});
[n_comb,~] = size(idx);
temp = cell(n_pipes,1);
valid_comb = [];
k = 1;
for k = 1:n_comb
for kk = 1:n_pipes
temp{kk} = pth{kk}{idx(k,kk)};
end
if my_intersect(temp{:})
valid_comb = [valid_comb k];
end
end
在这两种情况下,valid_comb
都有有效组合的索引,然后我可以使用类似的方法检索它们:
valid_idx = idx(valid_comb(1),:);
for k = 1:n_pipes
pth{k}{valid_idx(k)} % do something with this
end
当我用一些示例数据(pth
为 4x1
并且 pth
的 4 个元素为 2x1
、9x1
、8x1
和 69x1
),我得到了以下结果:
>> benchmark
Elapsed time is 51.9075 seconds.
valid_comb = 7112
Elapsed time is 66.6693 seconds.
valid_comb = 7112
所以疯狂物理学家的方法快了大约 15 秒。
我也误解了 mintersect
所做的,这不是我想要的。我想找到一个组合,其中两个或多个向量中不存在任何元素,所以我结束了编写我的 minintersect
版本:
function valid_comb = my_intersect(varargin)
% Returns true if a valid combination i.e. no combination of any 2 vectors
% have any elements in common
comb_idx = combnk(1:nargin,2);
[nr,nc] = size(comb_idx);
valid_comb = true;
k = 1;
% Use a while loop so that as soon as an intersection is found, the execution stops
while valid_comb && (k<=nr)
temp = intersect(varargin{comb_idx(k,1)},varargin{comb_idx(k,2)});
valid_comb = isempty(temp) && valid_comb;
k = k+1;
end
end
最佳答案
构建解决方案的几个有用要点:
- This post向您展示如何使用
ndgrid
在任意数组之间构造笛卡尔积. -
cellfun
同时接受多个元胞数组,您可以使用它们来索引特定元素。 - 您可以使用元胞数组从函数中捕获可变数量的参数,如图所示 here .
那么让我们输入 ndgrid
从你最外面的阵列:
grids = cellfun(@(x) 1:numel(x), pth, 'UniformOutput', false);
现在您可以创建一个包含网格乘积的索引:
index = cell(1, numel(pth));
[index{:}] = ndgrid(grids{:});
你想把所有的网格都做成列向量,然后横向拼接起来。该矩阵的行将代表笛卡尔索引以选择 pth
的元素。在每次迭代中:
index = cellfun(@(x) x(:), index, 'UniformOutput', false);
index = cat(2, index{:});
如果你翻一排index
到一个元胞数组中,你可以在 pth
上同步运行它选择正确的元素并调用 mintersect
关于结果。
for i = index'
indices = num2cell(i');
selection = cellfun(@(p, i) p{i}, pth, indices, 'UniformOutput', false);
mintersect(selection{:});
end
这是在假设 pth
的情况下编写的是一个行数组。如果不是这种情况,您可以将循环的第一行更改为 indices = reshape(num2cell(i), size(pth));
对于一般情况,只需 indices = num2cell(i);
对于列的情况。关键是来自 indices
的单元格形状必须与 pth
相同同步迭代它。它已经生成为具有相同数量的元素。
关于matlab - 当未明确知道输入参数的数量时,使用可变数量的输入参数调用函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61964257/