2010-07-12 4 views
8

У меня есть два массива ячеек строк, и я хочу проверить, содержат ли они одни и те же строки (они не должны быть в одном порядке, и мы не знаем, одинаковые длины).MATLAB: сравнение массивов ячеек строки

Например:

a = {'2' '4' '1' '3'}; 
b = {'1' '2' '4' '3'}; 

или

a = {'2' '4' '1' '3' '5'}; 
b = {'1' '2' '4' '3'}; 

Сначала я подумал о strcmp, но это потребует более зацикливания один содержимого ячейки и сравнить друг против друга. Я также рассмотрел ismember, используя что-то вроде:

ismember(a,b) & ismember(b,a) 

, но тогда мы не знаем заранее, что они имеют одинаковую длину (очевидный случай неравных). Итак, как бы вы могли выполнить это сравнение наиболее эффективным способом, не записывая слишком много случаев if/else.

ответ

17

Вы можете использовать функцию SETXOR, которая вернет значения, которые не находятся в пересечении двух массивов ячеек. Если она возвращает пустой массив, то две ячейки массива содержат одни и те же значения:

arraysAreEqual = isempty(setxor(a,b)); 



EDIT: Некоторые меры эффективности ...

Поскольку вы были любопытны о показателях эффективности, я думал, что проверю скорость своего решения против двух решений, перечисленных в Amro (которые используют ISMEMBER и STRCMP/CELLFUN). Я первый создал две большие ячейки массива:

a = cellstr(num2str((1:10000).')); %'# A cell array with 10,000 strings 
b = cellstr(num2str((1:10001).')); %'# A cell array with 10,001 strings 

Далее, я побежал каждое решение в 100 раз более, чтобы получить среднее время выполнения. Затем я поменял a и b и повторил его. Вот результаты:

Method  |  Time  | a and b swapped 
---------------+---------------+------------------ 
Using SETXOR | 0.0549 sec | 0.0578 sec 
Using ISMEMBER | 0.0856 sec | 0.0426 sec 
Using STRCMP |  too long to bother ;) 

Обратите внимание, что SETXOR решения неизменно быстрый выбор времени. Решение ISMEMBER будет работать немного быстрее, если a имеет элементы, которые не находятся в b. Это связано с short-circuit &&, который пропускает вторую половину расчета (поскольку мы уже знаем, что a и b не содержат одинаковых значений). Однако, если все значения в a также находятся в b, решение ISMEMBER значительно медленнее.

+1

Чтобы оценить производительность, вам понадобится другое решение для сравнения, например, предложение, сделанное с использованием цикла и [STRCMP] (http://www.mathworks.com/access/helpdesk/help/techdoc/ref/strcmp. HTML). Я предполагаю, что производительность будет прекрасной, но если вы обнаружите, что использование [SETXOR] (http://www.mathworks.com/access/helpdesk/help/techdoc/ref/setxor.html) действительно заканчивается тем, что узкое место в вашей обработке, вы можете попробовать посмотреть его исходный код ('type setxor' или' edit setxor') и переписать его, обрезая некоторую проверку ошибок и т. д. – gnovice

+1

спасибо, я думаю, я вижу, что @Mikhail пытался делать. Как насчет производительности? кажется, что XOR двух наборов - дорогостоящая операция, когда все, что мне нужно, - это истинный/ложный ответ – Dave

+0

oops, я отредактировал свой комментарий и испортил заказ .. извините – Dave

2

Посмотрите на функцию intersect

Что MATLAB Помощь говорит: векторы

[c, ia, ib] = intersect(a, b) также возвращает индекс столбца ia и ib таким образом, что c = a(ia) и b(ib) (или c = a(ia,:) и b(ib,:)).

+0

Я не уверен, как получить решение из результата 'intersect' – Dave

+0

Это зависит от того, что вам нужно делать. Если вам нужно скалярное логическое значение, что оба вектора содержат одинаковые строки, то решение gnovice является правильным ответом для вас. – Mikhail

5

Вы можете использовать функцию IsMember как вы сделали с небольшой модификацией:

arraysAreEqual = all(ismember(a,b)) && all(ismember(b,a)) 

Кроме того, вы можете написать версию петли с STRCMP одной строкой:

arraysAreEqual = all(cellfun(@(s)any(strcmp(s,b)), a)) 

EDIT: Я добавляю третье решение, адаптированное из другого SO question:

g = grp2idx([a;b]); 
v = all(unique(g(1:numel(a))) == unique(g(numel(a)+1:end))); 

В том же духе, Im, выполняется сравнение времени (с использованием функции TIMEIT):

function perfTests() 
    a = cellstr(num2str((1:10000)'));   %#' fix SO highlighting 
    b = a(randperm(length(a))); 

    timeit(@() func1(a,b)) 
    timeit(@() func2(a,b)) 
    timeit(@() func3(a,b)) 
    timeit(@() func4(a,b)) 
end 

function v = func1(a,b) 
    v = isempty(setxor(a,b));      %# @gnovice answer 
end 

function v = func2(a,b) 
    v = all(ismember(a,b)) && all(ismember(b,a)); 
end 

function v = func3(a,b) 
    v = all(cellfun(@(s)any(strcmp(s,b)), a)); 
end 

function v = func4(a,b) 
    g = grp2idx([a;b]); 
    v = all(unique(g(1:numel(a))) == unique(g(numel(a)+1:end))); 
end 

и результаты в том же порядке функций (чем ниже, тем лучше):

ans = 
    0.032527 
ans = 
    0.055853 
ans = 
     8.6431 
ans = 
    0.022362