Test for either of multiple string inside if statement conditions - matlab

I want to give the user the option of selecting a file (I know I've currently set it to choose a folder) or inputting numbers manually.
prompt = input('Do you want to manually input values or select file? :','s');
s2 = {'file','folder'; 'f','choose'};
tf = strcmp(prompt,s2);
if tf >= 1
folder_name = uigetdir
folder_name = uigetdir(start_path)
folder_name = uigetdir(start_path,dialog_title)
else
prompt = {'Enter matrix size:','Enter colormap name:'};
dlg_title = 'Input';
num_lines = 1;
defaultans = {'20','hsv'};
answer = inputdlg(prompt,dlg_title,num_lines,defaultans);
end
I want to allow the user to enter the words file, folder, f or choose and that to use the folder dialog box in the first part of the if statement and if either of these four strings haven't been inputted go to the else statement.
Since I'm saving them as strings I'm using strcmp. If I run the code and input the word 'folder' I'll get a matrix like:
0 1
0 0
My question is how do I use strcmp to say "if any element of the matrix is 1" that the logical output is now 1 and not 0.
Thanks for your help!

Just replace
if tf >= 1
with
if any(tf(:))
tf(:) returns a column vector of all elements in tf, and any() checks if there are any values greater than 1.

In addition to what Ian Riley had suggested, one can also use the following alternatives which rely on the "truthiness" of positive numbers:
nnz:
if nnz(tf)
sum:
if nnz(tf(:))
Both methods count nonzero elements in the array.

Related

Read specific portions of an excel file based on string values in MATLAB

I have an excel file and I need to read it based on string values in the 4th column. I have written the following but it does not work properly:
[num,txt,raw] = xlsread('Coordinates','Centerville');
zn={};
ctr=0;
for i = 3:size(raw,1)
tf = strcmp(char(raw{i,4}),char(raw{i-1,4}));
if tf == 0
ctr = ctr+1;
end
zn{ctr}=raw{i,4};
end
data=zeros(1,10); % 10 corresponds to the number of columns I want to read (herein, columns 'J' to 'S')
ctr=0;
for j = 1:length(zn)
for i=3:size(raw,1)
tf=strcmp(char(raw{i,4}),char(zn{j}));
if tf==1
ctr=ctr+1;
data(ctr,:,j)=num(i-2,10:19);
end
end
end
It gives me a "15129x10x22 double" thing and when I try to open it I get the message "Cannot display summaries of variables with more than 524288 elements". It might be obvious but what I am trying to get as the output is 'N = length(zn)' number of matrices which represent the data for different strings in the 4th column (so I probably need a struct; I just don't know how to make it work). Any ideas on how I could fix this? Thanks!
Did not test it, but this should help you get going:
EDIT: corrected wrong indexing into raw vector. Also, depending on the format you might want to restrict also the rows of the raw matrix. From your question, I assume something like selector = raw(3:end,4); and data = raw(3:end,10:19); should be correct.
[~,~,raw] = xlsread('Coordinates','Centerville');
selector = raw(:,4);
data = raw(:,10:19);
[selector,~,grpidx] = unique(selector);
nGrp = numel(selector);
out = cell(nGrp,1);
for i=1:nGrp
idx = grpidx==i;
out{i} = cell2mat(data(idx,:));
end
out is the output variable. The key here is the variable grpidx that is an output of the unique function and allows you to trace back the unique values to their position in the original vector. Note that unique as I used it may change the order of the string values. If that is an issue for you, use the setOrderparameter of the unique function and set it to 'stable'

searching matlab search path with strcmp

I have written the code below. Basically it is checking if some path is already in the matlab search path or not. If it is not found then it adds the path.
The problem is the strcmp always returns a vector of zeros despite the path actually already existing in currPath. I actually copied a path from currPath to check I was getting the correct values. Not sure why this is?
% get current path
currPath = strsplit(path, ';')';
currPath = upper(currPath);
% check if required paths exist - if not add them
pathsToCheck = ['C:\SOMEFOLDER\MADEUP'];
pathsToCheck = upper(pathsToCheck);
for n = 1 : length(pathsToCheck(:, 1))
index = strcmp(currPath, pathsToCheck(n, 1));
if sum(index) > 0
addpath(pathsToCheck{t, 1}, '-end'); % add path to the end
end
end
% save changes
savepath;
The issue is that you have defined pathsToCheck as a character array and not a cell array (which I think is what you intended the way that you are looping through it).
Rather than using a for loop, you could use ismember to check which members of a cell array of strings exist in another cell array of strings.
% Note the use of pathsep to make this work across multiple operating systems
currentPath = strsplit(path, pathsep);
pathsToCheck = {'C:\SOMEFOLDER\MADEUP'};
exists = ismember(pathsToCheck, currentPath);
% If you want to ignore case: ismember(upper(pathsToCheck), upper(currentPath))
% Add the ones that didn't exist
addpath(pathsToCheck{~exists}, '-end');

Counting occurrences of a character in a string within a cell

I'm having trouble figuring out how to count the occurrences of a character in a string within a cell. For example, I have a file that contains information like so:
type
m
mmNs
SmNm
and I'm trying to determine how many m's are in each line. To do this, I've tried this code:
sampleddata = dataset('file','sample.txt','Delimiter','\t');
muts = sampleddata.type;
fileID = fopen('number_occur.txt','w');
for j = 1:3
mutations = muts(j)
M = length(find(mutations == 'm'));
fprintf(fileID, '%1f\n',M)
end
fclose(fileID)
However, I get an error that informs me: "Undefined operator '==' for input arguments of type 'cell'." Does anyone know how to overcome this problem?
Gonna post a result here in case you did not find a way to do it. There are loads of ways to do it, I am just going to put one of them.
Basically, you want a regex to do string matches:
a = {'type';
'm';
'mmNs';
'SmNm';
'mmmmM'} %//Load in Data,
pattern = 'm'; %//The pattern you are looking for is 'm', it could be anything really, a number of specific word or a specific pattern
lines = regexp(a, pattern, 'tokens'); %// look for this pattern in each line
result = cellfun('length',lines); %//count the size of matched patterns, so each time it matches, the size should increase by 1.
This gives the result in a matrix form:
result =
0
1
2
2
4

MATLAB dir without '.' and '..'

the function dir returns an array like
.
..
Folder1
Folder2
and every time I have to get rid of the first 2 items, with methods like :
for i=1:numel(folders)
foldername = folders(i).name;
if foldername(1) == '.' % do nothing
continue;
end
do_something(foldername)
end
and with nested loops it can result in a lot of repeated code.
So can I avoid these "folders" by an easier way?
Thanks for any help!
Edit:
Lately I have been dealing with this issue more simply, like this :
for i=3:numel(folders)
do_something(folders(i).name)
end
simply disregarding the first two items.
BUT, pay attention to #Jubobs' answer. Be careful for folder names that start with a nasty character that have a smaller ASCII value than .. Then the second method will fail. Also, if it starts with a ., then the first method will fail :)
So either make sure you have nice folder names and use one of my simple solutions, or use #Jubobs' solution to make sure.
A loop-less solution:
d=dir;
d=d(~ismember({d.name},{'.','..'}));
TL; DR
Scroll to the bottom of my answer for a function that lists directory contents except . and ...
Detailed answer
The . and .. entries correspond to the current folder and the parent folder, respectively. In *nix shells, you can use commands like ls -lA to list everything but . and ... Sadly, MATLAB's dir doesn't offer this functionality.
However, all is not lost. The elements of the output struct array returned by the dir function are actually ordered in lexicographical order based on the name field. This means that, if your current MATLAB folder contains files/folders that start by any character of ASCII code point smaller than that of the full stop (46, in decimal), then . and .. willl not correspond to the first two elements of that struct array.
Here is an illustrative example: if your current MATLAB folder has the following structure (!hello and 'world being either files or folders),
.
├── !hello
└── 'world
then you get this
>> f = dir;
>> for k = 1 : length(f), disp(f(k).name), end
!hello
'world
.
..
Why are . and .. not the first two entries, here? Because both the exclamation point and the single quote have smaller code points (33 and 39, in decimal, resp.) than that of the full stop (46, in decimal).
I refer you to this ASCII table for an exhaustive list of the visible characters that have an ASCII code point smaller than that of the full stop; note that not all of them are necessarily legal filename characters, though.
A custom dir function that does not list . and ..
Right after invoking dir, you can always get rid of the two offending entries from the struct array before manipulating it. Moreover, for convenience, if you want to save yourself some mental overhead, you can always write a custom dir function that does what you want:
function listing = dir2(varargin)
if nargin == 0
name = '.';
elseif nargin == 1
name = varargin{1};
else
error('Too many input arguments.')
end
listing = dir(name);
inds = [];
n = 0;
k = 1;
while n < 2 && k <= length(listing)
if any(strcmp(listing(k).name, {'.', '..'}))
inds(end + 1) = k;
n = n + 1;
end
k = k + 1;
end
listing(inds) = [];
Test
Assuming the same directory structure as before, you get the following:
>> f = dir2;
>> for k = 1 : length(f), disp(f(k).name), end
!hello
'world
a similar solution from the one suggested by Tal is:
listing = dir(directoryname);
listing(1:2)=[]; % here you erase these . and .. items from listing
It has the advantage to use a very common trick in Matlab, but assumes that you know that the first two items of listing are . and .. (which you do in this case). Whereas the solution provided by Tal (which I did not try though) seems to find the . and .. items even if they are not placed at the first two positions within listing.
Hope that helps ;)
If you're just using dir to get a list of files and and directories, you can use Matlab's ls function instead. On UNIX systems, this just returns the output of the shell's ls command, which may be faster than calling dir. The . and .. directories won't be displayed (unless your shell is set up to do so). Also, note that the behavior of this function is different between UNIX and Windows systems.
If you still want to use dir, and you test each file name explicitly, as in your example, it's a good idea to use strcmp (or one of its relations) instead of == to compare strings. The following would skip all hidden files and folder on UNIX systems:
listing = dir;
for i = 1:length(listing)
if ~strcmp(listing(i).name(1),'.')
% Do something
...
end
end
You may also wanna exclude any other files besides removing dots
d = dir('/path/to/parent/folder')
d(1:2)=[]; % removing dots
d = d([d.isdir]) % [d.isdir] returns a logical array of 1s representing folders and 0s for other entries
I used: a = dir(folderPath);
Then used two short code that return struct:
my_isdir = a([a.isdir]) Get a struct which only has folder info
my_notdir = a(~[a.isdir]) Get a struct which only has non-folder info
Combining #jubobs and #Tal solutions:
function d = dir2(folderPath)
% DIR2 lists the files in folderPath ignoring the '.' and '..' paths.
if nargin<1; folderPath = '.'; elseif nargin == 1
d = dir(folderPath);
d = d(~ismember({d.name},{'.','..'}));
end
None of the above puts together the elements as I see the question having being asked - obtain a list only of directories, while excluding the parents.
Just combining the elements, I would go with:
function d = dirsonly(folderPath)
% dirsonly lists the unhidden directories in folderPath ignoring '.' and '..'
% creating a simple cell array without the rest of the dir struct information
if nargin<1; folderPath = '.'; elseif nargin == 1
d = dir(folderPath);
d = {d([d.isdir] & [~ismember({d.name},{'.','..'})]).name}.';
end
if hidden folders in general aren't wanted the ismember line could be replaced with:
d = {d([d.isdir] & [~strncmp({d.name},'.',1)]).name}.';
if there were very very large numbers of interfering non-directory files it might be more efficient to separate the steps:
d = d([d.isdir]);
d = {d([~strncmp({d.name},'.',1)]).name}.';
We can use the function startsWith
folders = dir("folderPath");
folders = string({folders.name});
folders = folders(~startsWith(folders,"."))
Potential Solution - just remove the fields
Files = dir;
FilesNew = Files(3:end);
You can just remove them as they are the first two "files" in the structure
Or if you are actually looking for specific file types:
Files = dir('*.mat');

Do the same for every part in listdlg (MATLAB)

I am writing a program and I am using listdlg. I want for each selection of the list to do the same thing BUT it will save them in different part(so that every option will have it's own - let's say- sub folder with its text files and they can be accessed for another function.
So this is my listdlg
global fileCount
F = listdlg('PromptString','Different types', 'SelectionMode',...
'single', 'ListString',{E}, 'Name','Select a type','ListSize',[230 130]);
where {E} is user's input, which might be 3 rows or 6 rows, how many he likes.
So I want if he uses the first row to ask for input and then save it for the first type
if F == 1
[file,path] = uigetfile ('*.txt','Select your text files',...
'MultiSelect','on');
file = cellstr(file);
for k = 1:length(file)
fileCount = length (file);
z = importdata(fullfile(path, file{k}));
end
end
the same will be done for the following types, meaning if he chooses the 2nd then the files will be saved for the 2nd file, but the files of the first type will not be overwrote. So he now has let's say Orange-10files; Pink-2files and Yellow-4files.
Is there a way I can do that? except using if and elseif for every of his choice?
I hope I was clear enough!
Thanks!
Assign E as a cell array rather than inserting it as a cell array in the listdlg call. I'm not entirely clear on your end goal, but this will take the user's selection of E's elements, open whatever files the user selects, and return the path and file name of those files with the added "color" folder:
E = {'Orange','Pink','Yellow'};
F = listdlg('PromptString','Different types', 'SelectionMode',...
'single', 'ListString',E, 'Name','Select a type','ListSize',[230 130]);
[files,path] = uigetfile ('*.txt','Select your text files',...
'MultiSelect','on');
files = cellfun(#(x) fullfile(path,E{F},x),files,'UniformOutput',false);