Binsearch in cell matrix in Matlab - arrays

I have a cell matrix with 2 rows - sorted cell array of different strings and array of numbers. Also I have an example string. It's guarantied that this string appears in the 1st row in the cell array. I want to get index of example's appearance in cell array of strings.
Is there any function in Matlab, that provides solving with logarithmic complexity (something like binary search)?

If you look at ismember code (type open ismember), you'll see that it basically
Checks if the array is sorted (by calling issorted);
If not, it sorts the array;
Then it applies binary search.
So you can directly use ismember.
Example:
>> strings = {'a', 'aa', 'be', 'day', 'yes'};
>> [tf, loc ] = ismember('day', strings);
>> loc
loc =
4
Or maybe modify ismember (save it with another name) to bypass step 1, since you already know your array is sorted.

Related

Get specific cells from a cell array

I have a numeric array sized 1000x1 which have values 0 and 1, called conditionArray.
I have a cell array called netNames with the same size (1000x1) and its cells contain string values (which are name of some circuit nets).
I want to extract net names which from netNames which their pairwise condition bit is 1 in conditionArray.
E.g. if conditionArray(100) is equal to extract its net name from netNames{100}.
Output of this process can be stored in an string array or cell array.
Are there any ways to do this operation with pairwise operations or I should use a for statement for this?
You shall check out cellfun in Matlab anytime you want to manipulate each element inside a cellarray without using a for loop.
As I understand, you have:
N = 1000;
% an array with 0s and 1s (this generates random 0s and 1s):
conditionArray = randi([0,1],N);
% a cell array with strings (this generates random 5-character strings):
netNames = cell(N);
netNames = cellfun(#(c)char(randi([double('a'),double('z')],1,5)), netNames, 'UniformOutput',false);
To extract the elements from netNames where conditionArray is 1, you can do:
netNames(conditionArray==1)
This uses logical indexing into the cell array.

MATLAB: use strcmp(s1,s2) for variable length vector with strings

I have a query which I am trying to solve
I know that one can use strcmp(s1,s2) to compare two different strings to see whether they are the same. It gives 1 if that is the case.
However, how would one tackle this problem if you have a variable length array full of strings and you want to the whether all strings in the array are the same.
For example: ['NACA64A010' 'NACA64A010' 'NACA64A010' 'NACA64A010'] we can see that all the strings are the same in this array. However, how would one go about with using strcmp(s1,s2).
Thanks guys!
If you want all pairwise comparisons between strings: call ndgrid to generate indices of all combinations, and then index into your cell array of strings and call strcmp:
x = {'NACA64A010' 'NACA64A010' 'NACA64A010' 'NACA64A010'};
[ii, jj] = ndgrid(1:numel(x));
result = strcmp(x(ii), x(jj));
In this case
result =
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
because all strings are the same.
You probably had a pairwise comparison using strcmp in mind, but you can use it directly on cell arrays:
x={'NACA64A010' 'NACA64A010' 'NACA64A010' 'NACA64A010'}
result=all(strcmpi(x{1},x(2:end)))
Compare the first element to the remaining elements. It returns true only if all elements are equal. For a pairwise comparison you could us:
[~,~,c]=unique(x);
result=bsxfun(#eq,c,c.')
If you're solving the problem with a matrix (i.e. every row is a string) there are no particularly nice solutions in my opinion, but if your strings are contained into a cell array, things are getting easier and nicer.
So we start by creating such cell array:
myStrings={'NACA64A010' 'NACA64A010' 'NACA64A010' 'NACA64A010'};
where each cell contains a string. This will make your code more robust as well since every string can have a different length (this is not true if you concatenate all your strings in a matrix).
Then you specify which string you want to find inside such cell array:
stringThatMustBeTested='NACA64A010';
Now you can use cellfun(), which is a function that applies another function to every cell of a given cell array as follows:
results=cellfun(#(x) strcmp(x,stringThatMustBeTested),myStrings);
Such line simply means "apply strcmp() to every generic cell x inside myStrings and compare the cell with stringThatMustBeTested".
Variable results will be a logical output in which element j will be true if the j-th cell in your cell array is equal to the string you want to test. If results is entirely composed by 1s (which you can check as if sum(results)==length(results)), then all the strings are the same in myStrings (given that stringThatMustBeTested is the unique string in your cell array but anyways, this solution can be extended to a broader string search inside a cell).

Cell array to matrix conversion in matlab

I would like to covert three <1xN cell> (A, B and C) into a single Nx3 matrix. Could someone help me with this?
C={{1xN}; {1xN}; {1xN}};
where each N is a number in single quotes, e.g.
C = {{'123123' ,'12324', ....N times}; {'123123', '12324', ....N times}; {'123123', '12324' ,....N times}}
Since a couple of them mentioned about the ridiculous input, this is the reason for having it in the above form.
The three nested array of cells are the results of a regexp where my string and expression are both strings. Therefore I have the output of regexp as three cell arrays of row vectors.
For e.g.
node_ids=regexp(nodes,'(?<=node id=")\d*','match');
I can use cat function and then use a str2double for all three cell arrays and finally form a matrix by cell2mat.
For e.g.
node_ids=cat(1,node_ids{:});node_ids=str2double(node_ids);
But this takes more time and has more LOC.
My question is can it be done with fewer lines of code?
I tried using the cat function but keep getting this error:
Cannot support cell arrays containing cell arrays or objects.
Your input data is pretty bad.... why are you using a nested array of cells where each element is a string?
In any case, assuming C is your original input data, do this:
C = {{'123123' '12324'}; {'123123' '12324'}; {'123123' '12324'}};
out = cellfun(#(x) cellfun(#str2num, x, 'uni', 0), C, 'uni', 0);
out = cell2mat(cellfun(#cell2mat, out, 'uni', 0));
First line is some dummy data. Next line first goes through every nested cell element over your cell array and converts the strings into numbers. However, these are still in cell arrays. As such, the next line converts each cell array in the nested cell into a matrix, then we merge all of the cells together into one final matrix.
We get:
>> out
out =
123123 12324
123123 12324
123123 12324

Matlab: Delete the item in an N-dimensional array whose Nth dimension is 1, where N is unknown?

I have an N-dimensional array of items whose last dimension is the index of the array.
For example, if the array A contained images, then A(:,:,:,1) would be the first image, A(:,:,:,2) would be the second image, and so forth.
Similarly, if the array just contained integers, then A(:,1) would be the first integer, A(:,2) would be the second integer, and so forth.
-=-=-=-
What I'm trying to do is delete the first item from A when I do not know ahead of time what dimensionality it is.
If A contains images, I want to do this:
A(:,:,:,1) = [];
If A contains integers, I want to do this:
A(:,1) = [];
The problem is since I don't know what dimensionality it is, I don't know how many colons to put, and I don't know how to denote "N-1 colons here" in Matlab.
I'm hoping there is a programmatic way to do this, but I frankly have no idea what to search for if this is possible.
You can either use cell to comma-separated list expansion:
%// Build cell: {':', ':', ..., ':', [1]}
I(1:ndims(A)-1) = {':'};
I{ndims(A)} = 1;
%// Expand cell to comma separated list and delete:
A(I{:}) = [];
Or convert to cell using num2cell and then convert back using cell2mat:
C = num2cell(A,1:ndims(A)-1);
A = cell2mat(C(2:end));
I guess that unless you really need n-dimensional arrays, doing this with a cell array of n-1 dimensional arrays instead (as is C in the above code) should be a smart move in terms of simplicity of notation.

What type of array should I use to combine numerical values and string values and have the ability to sort them in octave/matlab

I'm trying to link numerical (octave/matlab) values in an array to string values in the array how can I go about doing this. The reason I'm trying to do this is to sort the array based on the numerical values.
Example:
array=[1,2,'filename1';3,4,'filename2';5,6,'filename3'] (I know this is incorrect and will give an error)
This is what I'm trying to get it to look like so I can sort based on the first or the second column and have the third column be "linked" / follow the sort. (Please note the numbers will not be a sequential sequence like 1,2,3... I just used that as an example)
1,2,filename1
3,4,filename2
5,6,filename3
If I sort the first numerical column in descending order it should look like this
5,6,filename3
3,4,filename2
1,2,filename1
How can I go about doing this and still get the values of the array individually?
Example:
array(1,1) would be 5
and array(3,3) would be filename1
If you want to know, I plan on creating a playlist of wavfile names based on this sort.
Ps: I'm using Octave/Matlab
You can use 2 separate arrays, one with 2 columns of number and one with strings. When you sort the first array based on the first number, the function will return both the sorted list as well as the reordered indices. You can use the reordered indices to rearrange the strings.
It would be something like this:
[sort_list, indx] = sort(array1, 1);
array_string = array_strings[indx];
I don't think the access in that way is possible. Maybe you can do something similar with cells but I would be more expensive than using 2 arrays.
Use a cell arrray. You then sort using sortrows:
>> myCell = {1, 2, 'filename1';
3, 4, 'filename2';
5, 6, 'filename3'};
>> array = flipud(sortrows(myCell, 1)) %// "1" => col. "flipud" => descending
ans =
[5] [6] 'filename3'
[3] [4] 'filename2'
[1] [2] 'filename1'
>> array(1,1)
ans =
[5]
>> array(3,3)
ans =
'filename1'

Resources