Reputation: 75
I have a piece of code that works in the following way.
There is a matrix of size n x 2
. Each element is an integer between 1 and some maximum, say m
.
I want to search for rows in this matrix, that is, given [v1, v2]
, output the index of this.
Right now, I am using:
k = find(ismember(edges, [v1, v2], 'rows'));
However, this is the bottleneck in my code because this is in linear time.
I would like to implement some hashmap type structure for fast lookup. What would be an easy way to do this?
Upvotes: 2
Views: 198
Reputation: 125874
One option that gives me about a 30-40 times speedup over your code is doing the comparison for the entire first column, capturing a set of indices, then only checking the values of the second column at those indices:
ind = find(edges(:, 1) == v1);
k = ind(edges(ind, 2) == v2);
If you still need it done faster than that, you can use the containers.Map
class to precompute a mapping of every possible [v1 v2]
to the list of row indices where it occurs. One caveat is that the key type for the map can't be a vector of numbers, but since you are dealing with integers (ideally with m
not being prohibitively large) you can convert [v1 v2]
to a 2-character ASCII key. Here's how you can build the map:
mapObj = containers.Map('KeyType', 'char', 'ValueType', 'any');
[R, C] = meshgrid(1:m);
keys = [R(:) C(:)];
for keyIndex = 1:(m*m)
v = keys(keyIndex, :);
ind = find(edges(:, 1) == v(1));
mapObj(char(v)) = ind(edges(ind, 2) == v(2));
end
And you can access a value from the map very quickly like so:
k = mapObj(char([v1 v2]));
Upvotes: 0
Reputation: 781
R2016b and beyond:
find(all(edges == [v1 v2], 2))
Prior:
find(all(bsxfun(@eq, edges, [v1 v2]), 2))
Upvotes: 1
Reputation: 15867
Using accumarray can make an adjacency matrix to speed up your search:
A = accumarray(edges,1,[m m],@any,false)
and you can use indexing to search it
if(A(v1,v2))...
If m
is very large you can create a sparse matrix:
A = accumarray(edges,1,[m m],@any,false,true)
Or if you need index of it the adjacency matrix can be cereated this way:
A = accumarray(edges,1:size(edgaes,1),[m m],@any,0,true);
so
index = A(v1,v2)
Upvotes: 0
Reputation: 114
Try the following code:
M = [5 2; 10 1; 3 2; 4 4; 5 0]
N = [4 4]
ind=find(all(repmat(N,size(M,1),1)==M,2));
ind is the row where the matrix include the specific numbers in N.
Upvotes: 0
Reputation: 607
Since you know the number of columns how about this (assuming edges is the matrix to be searched):
idx = find(edges(:,1)==v1 & edges(:,2)==v2);
Note, that depending on how exactly you use the index you might be better off using the logical index that is created on the way:
idx = edges(:,1)==v1 & edges(:,2)==v2;
Hope this helps.
Upvotes: 1