MATLAB: сравнение массивов строк - PullRequest
8 голосов
/ 12 июля 2010

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

Например:

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.

Ответы [ 3 ]

17 голосов
/ 12 июля 2010

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

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



РЕДАКТИРОВАТЬ: Некоторые показатели производительности ...

Поскольку вам было любопытно узнать показатели производительности, я решил проверить скорость своего решения по двум решениям, перечисленным в 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.Это связано с коротким замыканием &&, которое пропускает вторую половину вычисления (поскольку мы уже знаем, что a и b не содержат одинаковые значения).Однако, если все значения в a также указаны в b, решение ISMEMBER будет значительно медленнее.

5 голосов
/ 13 июля 2010

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

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

Также вы можете записать версию цикла с STRCMP в одну строку:

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

РЕДАКТИРОВАНИЕ: Я добавляю третье решение, адаптированное из другого ТАК вопрос :

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

В том же духе, я выполнил сравнение времени (используяфункция 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
2 голосов
/ 12 июля 2010

Взгляните на функцию intersect

Что говорит справка MATLAB:

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

...