Find strings that contain multiple substrings at the same time
25 visualizaciones (últimos 30 días)
Mostrar comentarios más antiguos
SpeedyGonzales
el 8 de Abr. de 2015
Editada: Jos (10584)
el 9 de Abr. de 2015
Hi, I have a array of strings and I would like to identify all those entries that contain two substrings at the same time. For example:
My strings are: 'First Example','Second Example', 'Third Example'
My Substrings are: 'irs','xam'
So I would like to identify the first string as the only one which contains both substrings. I have found a solution, but I am convinced that there must be a more elegant and efficient way of achieving this. My code looks as follows:
clear;clc;
%set variables
rbCode = {'RB_DEP_LI_EQ_EED'; ...
'RB_DEP_LI_EQ_EED_INV'; ...
'RB_DEP_LI_EQ_EED_TRS'; ...
'RB_DEP_LI_EQ_IED'
'RB_DEP_LI_EQ_IED_INV'; ...
'RB_DEP_LI_EQ_IED_TRS'; ...
'RB_DEP_LI_FI_INV'};
rbMarketValue = {100; 80; 20; 70; 40; 30; 20};
%compare invested market value
strToFind ={'EQ';'_INV'};
%sum up rbMarketValue for all rbCodes that have both 'EQ' and '_INV' in
%their name
a = arrayfun(@(x) strfind(rbCode,char(strToFind(x))),1:size(strToFind),'un',false);
a1 = arrayfun(@(x) logical(~isempty(cell2mat(a{1,1}(x,1)))),1:size(rbCode));
a2 = arrayfun(@(x) logical(~isempty(cell2mat(a{1,2}(x,1)))),1:size(rbCode));
a3 = sum([a1' a2'],2);
a4 = cell2mat(rbMarketValue);
sumDeptInv = sum(a4(a3==2));
Any suggestion how I can achieve this? Thanks Sven
2 comentarios
dpb
el 8 de Abr. de 2015
regular expressions (but I'm such a feeb I'll leave the actual expression to someone who can write it w/o having to read the full text... :) )
Stephen23
el 8 de Abr. de 2015
Is the order of the substrings known and fixed? If they have a fixed order, then this could be solved using a simple regular expression. If the order is not known, as your code currently solves, then this requires either two parses of the strings or some kind of pre-processing.
Respuesta aceptada
Stephen23
el 8 de Abr. de 2015
Editada: Stephen23
el 9 de Abr. de 2015
Actually using strfind is often faster than using regexp, and it has the significant advantage that all characters are interpreted literally (and not as special characters like with regexp). strfind can be used quite compactly for your task:
rbCode = {'RB_DEP_LI_EQ_EED'; ...
'RB_DEP_LI_EQ_EED_INV'; ...
'RB_DEP_LI_EQ_EED_TRS'; ...
'RB_DEP_LI_EQ_IED'
'RB_DEP_LI_EQ_IED_INV'; ...
'RB_DEP_LI_EQ_IED_TRS'; ...
'RB_DEP_LI_FI_INV'};
strToFind ={'EQ';'_INV'};
>> fun = @(s)~cellfun('isempty',strfind(rbCode,s))
>> out = cellfun(fun,strToFind,'UniformOutput',false)
>> idx = all(horzcat(out{:}),2)
idx =
0
1
0
0
1
0
0
2 comentarios
Jos (10584)
el 9 de Abr. de 2015
Editada: Jos (10584)
el 9 de Abr. de 2015
Here is a REGEXP way of solving this (but I also prefer the strained solution posted by Stephen!)
tf = cellfun(@(x) numel(x)==2,regexp(rbCode,sprintf('%s|',strToFind{:})))
Más respuestas (1)
Sven
el 8 de Abr. de 2015
Editada: Sven
el 8 de Abr. de 2015
Hi Sven,
Here's how I would do it. It uses a call to regexp (you could also use strsplit) and one cellfun. The good thing about building a lookup table is that if your data is very large, there will only be an initial "hit" in terms of string comparison processing to build the lookup table, and after that you will be dealing with logical masks so any subsequent questions you ask (say, if you chose a different pair of codes) will be very efficient:
% Set up your problem
rbCode = {'RB_DEP_LI_EQ_EED'; ...
'RB_DEP_LI_EQ_EED_INV'; ...
'RB_DEP_LI_EQ_EED_TRS'; ...
'RB_DEP_LI_EQ_IED'
'RB_DEP_LI_EQ_IED_INV'; ...
'RB_DEP_LI_EQ_IED_TRS'; ...
'RB_DEP_LI_FI_INV'};
rbMarketValues = [100; 80; 20; 70; 40; 30; 20];
strToFind ={'EQ';'INV'};
% Find all codes and build a lookup table showing which are present
rbToks = regexp(rbCode,'_','split');
codes = unique([rbToks{:}]); % You won't need this if you already have a list
codeLookup = cell2mat(cellfun(@(tok)ismember(codes,tok),rbToks,'Un',0));
% Look in your lookup to see which entries have both codes
hasBothMask = all(codeLookup(:,ismember(codes,strToFind)),2);
sumDeptInv = sum(rbMarketValues(hasBothMask))
Did that make sense?
Thanks,
Sven.
Ver también
Categorías
Más información sobre Characters and Strings en Help Center y File Exchange.
Productos
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!