2011-03-17 35 views
1

我需要在一組單元陣列中找到唯一的單元陣列。例如,如果這是我輸入:如何在MATLAB中的一組單元陣列中有效地找到獨特的單元陣列?

I = {{'a' 'b' 'c' 'd' 'e'} ... 
    {'a' 'b' 'c'} ... 
    {'d' 'e'} ... 
    {'a' 'b' 'c' 'd' 'e'} ... 
    {'a' 'b' 'c' 'd' 'e'} ... 
    {'a' 'c' 'e'}}; 

然後,我想我的輸出看起來像這樣:

I_unique = {{'a' 'b' 'c' 'd' 'e'} ... 
      {'a' 'b' 'c'} ... 
      {'d' 'e'} ... 
      {'a' 'c' 'e'}}; 

你有任何想法如何做到這一點?輸出中元素的順序無關緊要,但效率確實很高,因爲單元陣列可能非常大。

+0

細胞是否在輸出此事的順序?你是否按照它們出現在輸入中的順序需要它們?另外,你是否正在處理*很多細胞進行比較(即速度問題)? – gnovice 2011-03-17 17:22:38

+0

您是否打算讓每個單元格包含帶單引號的單個字符串或包含單字符字符串的列表?你得到了前者 - 一個字符串「在」裏面的加倍引號只是一個轉義引用。爲了得到後者,用空格拆分字符串文字,如{'a''b''c''d''e'}。 – 2011-03-17 18:00:04

+0

嗨,順序無關緊要。計算時間很重要,因爲輸入數據可能很大。對不起,我沒有指定此問題 - 一個單元中的元素可能包含多個字符,即{'a1''a2''a3'}。 – user664664 2011-03-17 19:23:39

回答

1

如果你的細胞只含有分類單個字符,那麼你可以使用保留只是獨特的序列:

 
>> I = {{'a' 'b' 'c' 'd' 'e'} {'a' 'b' 'c'} {'d' 'e'} {'a' 'b' 'c' 'd' 'e'} {'a' 'b' 'c' 'd' 'e'} {'a' 'c' 'e'}}; 
>> I_unique = cellfun(@char, I, 'uniformoutput', 0); 
>> I_unique = cellfun(@transpose, I_unique, 'uniformoutput', 0); 
>> I_unique = unique(I_unique) 

I_unique = 

    'abc' 'abcde' 'ace' 'de' 

然後,您可以再次分裂所產生的細胞成單個字符:

 
>> I_unique = cellfun(@transpose, I_unique, 'uniformoutput', 0); 
>> I_unique = cellfun(@cellstr, I_unique, 'uniformoutput', 0); 
>> I_unique = cellfun(@transpose, I_unique, 'uniformoutput', 0); 
>> I_unique{:} 

ans = 

    'a' 'b' 'c' 


ans = 

    'a' 'b' 'c' 'd' 'e' 


ans = 

    'a' 'c' 'e' 


ans = 

    'd' 'e' 
+0

非常感謝您的回答。 – user664664 2011-03-17 19:05:05

1

編輯:已更新爲使用更高效的算法。

如果效率相當於I中的大量集合,那麼您的最佳選擇可能是推出自己的優化循環。這個問題與前面關於how to efficiently remove sets that are subsets of or equal to another的問題有一些相似之處。這裏的區別在於你不關心刪除子集,只是重複,所以my answer to the other question中的代碼可以修改,以進一步減少進行比較的次數。

首先我們可以認識到,比較具有不同數量元素的集合沒有意義,因爲它們在這種情況下不可能匹配。因此,第一步是計算每個集合中的字符串數量,然後遍歷每個具有相同字符串數量的集合組。

對於這些組中的每個組,我們將有兩個嵌套循環:每個集合的外部循環從集合的結尾開始,以及一個內部循環遍佈在每個集合的前面。如果/當找到第一個匹配時,我們可以將該集合標記爲「不唯一」,並打破內部循環以避免額外的比較。在集合的末尾啓動外部循環會給我們額外的獎勵,在I_unique中設置的額外獎勵將保持I的出現順序。

這裏是生成的代碼:

I = {{'a' 'b' 'c' 'd' 'e'} ... %# The sample cell array of cell arrays of 
    {'a' 'b' 'c'} ...   %# strings from the question 
    {'d' 'e'} ... 
    {'a' 'b' 'c' 'd' 'e'} ... 
    {'a' 'b' 'c' 'd' 'e'} ... 
    {'a' 'c' 'e'}}; 
nSets = numel(I);     %# The number of sets 
nStrings = cellfun('prodofsize',I); %# The number of strings per set 
uniqueIndex = true(1,nSets);   %# A logical index of unique elements 

for currentSize = unique(nStrings) %# Loop over each unique number of strings 

    subIndex = find(nStrings == currentSize); %# Get the subset of I with the 
    subSet = I(subIndex);      %# given number of strings 

    for currentIndex = numel(subSet):-1:2  %# Outer loop 
    for compareIndex = 1:currentIndex-1  %# Inner loop 
     if isequal(subSet{currentIndex},subSet{compareIndex}) %# Check equality 
     uniqueIndex(subIndex(currentIndex)) = false; %# Mark as "not unique" 
     break        %# Break the inner loop 
     end 
    end 
    end 

end 

I_unique = I(uniqueIndex); %# Get the unique values 
+0

非常感謝,這正是我需要的。 – user664664 2011-03-17 19:05:50