在 Matlab 中搜索多维数组中的一维序列
Search for 1-D sequence in multidimensional array in Matlab
我有一个 n 维数组,并且我在所有其他维度上的某个位置沿一个维度有一个序列。我如何找到这个序列的位置?最好没有循环。
我用的是matlab。我知道它应该在哪个维度,但顺序不一定在那里。查找和 == 不起作用。我可以使用互相关创建一个 nd find 函数,但我猜这已经实现了,我只是不知道要调用什么函数。
示例:
ND = rand(10,10,10,10);
V = ND(randi(10),randi(10),randi(10),:);
[I1, I2, I3] = find(ND==V);
编辑:要找到的序列跨越它所在的整个维度,我在问题的原始表述中没有提到这一点。 Knedlsepp 的解决方案完全解决了我遇到的问题,但 Luis 的解决方案解决了一个更普遍的问题,即当序列不一定跨越整个维度时。
由于有多种方法可以解释您的问题,我将澄清:此方法假定一维序列大小:numel(V) == size(ND, dimToSearch)
。因此,对于 V = [1,2]
和 ND = [1,2,1,2]
它不适用。如果您想要此功能,请使用 Luis Mendo 的答案,否则这可能会更快。
这将是使用 bsxfun
:
的绝好机会
我们从一些示例数据开始:
ND = rand(10,10,10,10);
V = ND(3,2,:,3);
如果您没有以正确的维度给出向量 V
(在本例中为 [1,1,10,1]
),您可以按以下方式对其进行整形:
dimToSearch = 3;
Vdims = ones(1, ndims(ND));
Vdims(dimToSearch) = numel(V);
V = reshape(V, Vdims);
现在我们生成一个单元格来保存匹配项的索引:
I = cell(1, ndims(ND));
此时我们计算 ND
的大小,如果它沿着维度 dimToSearch
折叠(我们根据 V
计算 dimToSearch
,因为此时它将具有正确的尺寸):
dimToSearch = find(size(V)>1);
collapsedDims = size(ND);
collapsedDims(dimToSearch) = 1;
最后是我们实际寻找模式的部分:
[I{:}] = ind2sub(collapsedDims, find(all(bsxfun(@eq, ND, V), dimToSearch)));
这是通过以下方式完成的:bsxfun(@eq, ND, V)
将隐式 repmat
数组 V
因此它与 ND
具有相同的维度并进行相等比较。在此之后,我们使用 all
检查维度 dimToSearch
中的所有条目是否相等。然后调用 find
和 ind2sub
将为您的数据生成正确的索引。
一种不太理想的方法:
dims = size(ND);
Vrep = repmat(V, [dims(1), dims(2), dims(3), 1]);
ND_V_dist = sqrt(sum(abs(ND.^2-Vrep.^2), 4));
iI = find(ND_V_dist==0);
[I1, I2, I3] = ind2sub([dims(1), dims(2), dims(3)], iI);
设 d
为搜索的维度。我假设寻找的序列 V
可能比 size(ND,d)
短。所以序列可能出现一次,不止一次,或者永远不会出现在每个维度上-d
-"thread".
以下代码使用 num2cell
to reshape ND
into a cell array such that each dimension-d
-thread is in a different cell. Then strfind
应用于每个单元格以确定与 V
的匹配,结果是一个与 ND
具有相同维度的单元格数组,但其中维度 d
是单例。每个单元格的内容告诉匹配的 d
-维位置,如果有的话。
感谢 @knedlsepp 提出的使用 num2cell
的建议,这大大简化了代码。
ND = cat(3, [1 2 1 2; 3 4 5 6],[2 1 0 5; 0 0 1 2] ); %// example. 2x4x2
V = 1:2; %// sought pattern. It doesn't matter if it's a row, or a column, or...
d = 2; %// dimension along which to search for pattern V
result = cellfun(@(x) strfind(x(:).', V(:).'), num2cell(ND,d), 'UniformOutput', 0);
这给
ND(:,:,1) =
1 2 1 2
3 4 5 6
ND(:,:,2) =
2 1 0 5
0 0 1 2
V =
1 2
result{1,1,1} =
1 3 %// V appears twice (at cols 1 and 3) in 1st row, 1st slice
result{2,1,1} =
[] %// V doesn't appear in 2nd row, 1st slice
result{1,1,2} =
[] %// V appears appear in 1st row, 2nd slice
result{2,1,2} =
3 %// V appears once (at col 3) in 2nd row, 2nd slice
我有一个 n 维数组,并且我在所有其他维度上的某个位置沿一个维度有一个序列。我如何找到这个序列的位置?最好没有循环。
我用的是matlab。我知道它应该在哪个维度,但顺序不一定在那里。查找和 == 不起作用。我可以使用互相关创建一个 nd find 函数,但我猜这已经实现了,我只是不知道要调用什么函数。
示例:
ND = rand(10,10,10,10);
V = ND(randi(10),randi(10),randi(10),:);
[I1, I2, I3] = find(ND==V);
编辑:要找到的序列跨越它所在的整个维度,我在问题的原始表述中没有提到这一点。 Knedlsepp 的解决方案完全解决了我遇到的问题,但 Luis 的解决方案解决了一个更普遍的问题,即当序列不一定跨越整个维度时。
由于有多种方法可以解释您的问题,我将澄清:此方法假定一维序列大小:numel(V) == size(ND, dimToSearch)
。因此,对于 V = [1,2]
和 ND = [1,2,1,2]
它不适用。如果您想要此功能,请使用 Luis Mendo 的答案,否则这可能会更快。
这将是使用 bsxfun
:
我们从一些示例数据开始:
ND = rand(10,10,10,10);
V = ND(3,2,:,3);
如果您没有以正确的维度给出向量 V
(在本例中为 [1,1,10,1]
),您可以按以下方式对其进行整形:
dimToSearch = 3;
Vdims = ones(1, ndims(ND));
Vdims(dimToSearch) = numel(V);
V = reshape(V, Vdims);
现在我们生成一个单元格来保存匹配项的索引:
I = cell(1, ndims(ND));
此时我们计算 ND
的大小,如果它沿着维度 dimToSearch
折叠(我们根据 V
计算 dimToSearch
,因为此时它将具有正确的尺寸):
dimToSearch = find(size(V)>1);
collapsedDims = size(ND);
collapsedDims(dimToSearch) = 1;
最后是我们实际寻找模式的部分:
[I{:}] = ind2sub(collapsedDims, find(all(bsxfun(@eq, ND, V), dimToSearch)));
这是通过以下方式完成的:bsxfun(@eq, ND, V)
将隐式 repmat
数组 V
因此它与 ND
具有相同的维度并进行相等比较。在此之后,我们使用 all
检查维度 dimToSearch
中的所有条目是否相等。然后调用 find
和 ind2sub
将为您的数据生成正确的索引。
一种不太理想的方法:
dims = size(ND);
Vrep = repmat(V, [dims(1), dims(2), dims(3), 1]);
ND_V_dist = sqrt(sum(abs(ND.^2-Vrep.^2), 4));
iI = find(ND_V_dist==0);
[I1, I2, I3] = ind2sub([dims(1), dims(2), dims(3)], iI);
设 d
为搜索的维度。我假设寻找的序列 V
可能比 size(ND,d)
短。所以序列可能出现一次,不止一次,或者永远不会出现在每个维度上-d
-"thread".
以下代码使用 num2cell
to reshape ND
into a cell array such that each dimension-d
-thread is in a different cell. Then strfind
应用于每个单元格以确定与 V
的匹配,结果是一个与 ND
具有相同维度的单元格数组,但其中维度 d
是单例。每个单元格的内容告诉匹配的 d
-维位置,如果有的话。
感谢 @knedlsepp 提出的使用 num2cell
的建议,这大大简化了代码。
ND = cat(3, [1 2 1 2; 3 4 5 6],[2 1 0 5; 0 0 1 2] ); %// example. 2x4x2
V = 1:2; %// sought pattern. It doesn't matter if it's a row, or a column, or...
d = 2; %// dimension along which to search for pattern V
result = cellfun(@(x) strfind(x(:).', V(:).'), num2cell(ND,d), 'UniformOutput', 0);
这给
ND(:,:,1) =
1 2 1 2
3 4 5 6
ND(:,:,2) =
2 1 0 5
0 0 1 2
V =
1 2
result{1,1,1} =
1 3 %// V appears twice (at cols 1 and 3) in 1st row, 1st slice
result{2,1,1} =
[] %// V doesn't appear in 2nd row, 1st slice
result{1,1,2} =
[] %// V appears appear in 1st row, 2nd slice
result{2,1,2} =
3 %// V appears once (at col 3) in 2nd row, 2nd slice