У меня есть переменная pth
, которая представляет собой массив ячеек размера 1xn
, где n
- пользовательский ввод. Каждый из элементов в pth
сам по себе является массивом ячеек, а length(pth{k})
для k=1:n
является переменным (результатом другой функции). Каждый элемент pth{k}{kk}
, где k=1:n
и kk=1:length(pth{k})
- это одномерный вектор целых чисел / номеров узлов снова переменной длины. Итак, чтобы подвести итог, у меня есть переменное количество векторов переменной длины, организованных в доступное количество массивов ячеек.
Я хотел бы попытаться найти все возможные пересечения, когда вы берете вектор наугад из pth{1}
, pth{2}
, {pth{3}
и т. Д. В обмене файлами есть различные функции, которые, кажется, делают это, например этот или этот. У меня проблема в том, что вам нужно вызвать функцию следующим образом:
mintersect(v1,v2,v3,...)
и я не могу записать все входы в общем случае, потому что я не знаю явно, сколько их (это было бы 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...
продолжайте перебирать все возможные комбинации, но я не могу написать это в коде. Эта функция из File Exchange выглядит как хороший способ найти все возможные комбинации, но опять же у меня такая же проблема с вызовом функции с переменным количеством входов:
allcomb(1:length(pth{1}),1:length(pth{2}),...,1:length(pth{n}))
Кто-нибудь знает, как обойти эту проблему вызовов функций с переменным количеством входных аргументов, когда вы не можете физически указать все входные аргументы, потому что их количество является переменным? Это в равной степени относится к MATLAB и Octave, следовательно, к двум тегам. Любые другие предложения о том, как найти все возможные комбинации / пересечения при случайном взятии вектора из каждого pth{k}
приветствуются!
ИЗМЕНИТЬ 27.05.20
Благодаря ответу Безумного физика я в конечном итоге использовал следующее, которое работает:
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
, а 4 элемента pth
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
, а это не то, что я хотел. Я хотел найти комбинацию, в которой элемент не присутствует в двух или более векторах, поэтому я закончил писать свою версию mintersect
:
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