Please help me with the following problem:
In matlab, I have an Nx3 char variable, where N can vary depending on the input.
Let's say N = 5 and I have the following variable A (5x3 char):
A = [' 1Y';
' 5Y';
'10Y';
'15Y';
'20Y']
Is there a way to define a new variable B having as values the numbers in variable A, i.e. B=[1; 5; 10; 15; 20]?
Thank you for your help!
Since your input is a character array, first convert each row into a cell to allow use with the string functions in MATLAB:
out = mat2cell(val, ones(size(val,1),1));
mat2cell converts a matrix into a series of cells. In our case, you would like to have 5 cells, or as many cells as there are rows in your matrix val and each cell will be as long as the total number of column in val.
Once you do this, you can replace the Y strings with nothing, then convert to numbers:
out = strrep(out, 'Y', '');
out2 = cellfun(#str2num, out);
The first line uses strrep to replace any instances of Y with nothing, and then we apply str2num on each of the cells to convert the trimmed string into an actual number. This is through the use of cellfun so that we can iterate through each cell apply str2num to each cell.
We get:
out2 =
1
5
10
15
20
To be fully reproducible:
val = ['1Y '; '5Y '; '10Y'; '15Y'; '20Y'];
out = mat2cell(val, ones(size(val,1),1), size(val,2));
out = strrep(out, 'Y', '');
out2 = cellfun(#str2num, out);
Suppose you have the following:
A = [' 1Y';
' 5Y';
'10Y';
'15Y';
'20Y';]
Then this should do the trick:
B=A'
C=strsplit(B(:)','Y')
V=cellfun(#str2num,C(1:end-1))
This is how you can convert a cellstr to its numeric value:
a = {'1'};
ans1 = int64(str2num(a{1}));
Related
I have a cell with mathematical expressions that I would like to convert to a numeric array. It look as follows:
a = {};
a{1,1} = '0.55';
a{2,1} = '0.25 + 0.50';
Now I would like to receive the result (but preferably without a for loop):
b(1) = 0.55;
b(2) = 0.75;
How can I achieve this efficiently?
b = cellfun(#eval,a); will create an array b of the same size as cell array a, with each value the evaluation of the corresponding string in the cell array.
a = {};
a{1,1} = '0.55';
a{2,1} = '0.25 + 0.50';
a=repmat(a,1000,20); %Make it big for performance evaluation
tic
b1 = cellfun(#eval,a);
toc %0.662187 seconds
Another option is to make a big string expression so that eval is called only once rather than several times due to cellfun internal loop. This is less safe as abnormal values in the cell array a will likely cause the code to crash, while it may simply produce NaN in the code above.
tic
% add a comma separator after each value
strCell = cellfun(#(x) [x ','],transpose(a),'uniformoutput',false);
% add a semicolon separator at the end of each row
strCell(end,:) = cellfun(#(x) [x(1:end-1) ';'], strCell(end,:), 'uniformoutput',false);
% remove the last separator
strCell{end}=strCell{end}(1,end-1);
% evaluate the line
b2=eval(['[' strCell{:} ']']);
toc %0.313738 seconds but sometimes more than 1 seconds
For example, I have this Matrix:
a=[100,20,3,2000]
I want to save every integer in 4 places in string. However the last integer matrix will be
s='0100002000032000'
s = ''
for i = 1:size(a, 2)
s = [s sprintf('%04d', a(i))]
end
Or, even simpler, do:
s = num2str(a, '%04d')
I have a vector, A=[2 2 4 5]. I want to convert A to a number. Answer should be 2245.
Example 2. B=[5,6,7,8,9]. Answer should be 56789.
Thanks.
PS. Thanks to all. Now I understand to convert the vector to a string and delete the space, and convert back to a number.
You could try this -
>> a = [2 3 10];
>> str2num(strrep(num2str(a), ' ', ''))
ans =
2310
Why does it work? Well, num2str ("number to string") converts the vector into its character representation
>> num2str(a)
ans =
2 3 10
which is almost what you want, except for the spaces between the numbers. So you call strrep ("string replace") to replace all the spaces (' ') with the empty string ('')
>> strrep('hi there', ' ', '')
ans =
hithere
and finally use str2num ("string to number") to convert the resulting string back into a number.
Take each number, convert it to a string and concatenate the results. Take this string and convert it back into a number. You can use num2str on the array, remove any white spaces that result from this conversion using ismember then convert the string back to a number with num2str:
C = [2 3 10];
strC = num2str(C);
strC(ismember(strC, ' ')) = [];
out = str2num(strC)
out =
2310
Alternatively, you can use strrep to replace all spaces with nothing after you run num2str, then convert back to a number:
C = [2 3 10];
strC = num2str(C);
strC = strrep(strC, ' ', '');
out = str2num(strC)
out =
2310
Tipping the hat to Chris Taylor, this can all be done in one line:
out = str2num(strrep(num2str(C), ' ', ''))
out =
2310
One more for academic purposes is to use regular expressions. Specifically, use regexprep on the converted string array that is output from num2str and replace all spaces with nothing:
C = [2 3 10];
strC = num2str(C);
out = str2num(regexprep(strC, '\s*', ''))
out =
2310
The pattern \s* searches for 0 or more white space characters. We find these and set them to nothing.
Thanks to #obchardon for a correction.
This uses only arithmetics (no strings). It works for numbers greater than 0. A can be a row or column vector.
A = [2 0 3 10];
x = cumsum(floor(log10(A.'+(A.'==0)))+1);
x = x(end)-x;
result = A(:).'*10.^x
which gives
result =
20310
If you want to string all of the digits together like they are the digits in a single integer you can convert the vector to a string, remove the spaces to smoosh the digits together, and then convert it back to a single number.
This way will handle an arbitrary number of digits in each vector element (assuming they are all real integers) rather than trying to multiply each element by the respective power of 10 and taking the sum.
Example code:
A = [2 44 12 6];
Astr = num2str(A);
Astr(strfind(Astr, ' ')) = [];
Anum = str2double(Astr);
This uses num2str without having to worry about whitespaces.
Apply num2str to every number using arrayfun, concatenate the resulting strings, convert back to number. Sadly it is quite a bit slower than the whitespace-deleting or numerical approach.
numStrings = arrayfun(#num2str,a,'uni',0);
out = str2num(cat(2,numStrings{:}))
out =
2310
I'm looking for a really quick method in MATLAB of searching for a specific digit within an integer, ideally in a given position. For example:
Simple case...
I want to look through an array of integers and return all those which contain the number 1 eg 1234, 4321, 6515, 847251737 etc
More complex case...
I want to loop through an array of integers and return all those which contain the number 1 in the third digit eg 6218473, 541846, 3115473 BUT 175846 would not be returned.
Any thoughts?
There's a few answers here already, I'll throw my try into the pot.
Conversion to string can be expensive, so if it can be avoided, it should be.
n = 1:100000; % sample numbers
m = 3; % digit to check
x = 1; % number to find
% Length of the numbers in digits
num_length = floor(log10(abs(n)))+1;
% digit (from the left) to check
num_place = num_length-m;
% get the digit
digit_in_place = mod(floor(abs(n)./(10.^num_place)),10);
found_number = n(digit_in_place==x);
By casting to strings, the trick to vectorising is just to make sure x is a column vector. x(:) guarantees this. Also you need to left-align the strings which is done with the format specifier '%-d' where - is for left-alignment and d is for integers:
s = num2str(x(:), '%-d');
ind = s(:,3)=='1'
and this also allows you to easily solve your first case:
ind = any(s=='1',2)
in either case to recover your original number just go:
x(ind)
One way of getting there is to cast your numbers as strings and then check if the 3rd position of that string is '1'. It works perfectly fine in a loop, but I am confident that there is also a vectorized solution:
numbers = [6218473, 541846, 3115473, 175846]'
returned_numbers = [];
for i = 1:length(numbers)
number = numbers(i);
y = sprintf('%d', number) %// cast to string
%// add number to list, if its third character is 11
if strcmp(y(3), '1')
returned_numbers = [returned_numbers, number];
end
end
% // it returns:
returned_numbers =
6218473 541846 3115473
Code
%// Input array
array1 = [-94341 1234 4321 6515 847251737 6218473 541846 3115473 175846]
N = numel(array1); %// number of elements in input array
digits_sep = num2str(array1(:))-'0'; %//' Seperate the digits into a matrix
%// Simple case
output1 = array1(any(digits_sep==1,2))
%// More complex case output
col_num = 3;
%// Get column numbers for each row of the digits matrix and thus
%// the actual linear index corresponding to 3rd digit for each input element
ind1 =sub2ind(size(digits_sep),1:N,...
size(digits_sep,2)-floor(log10(abs(array1))-col_num+1));
%// Select the third digits, check which ones have `1` and use them to logically
%// index into input array to get the output
output2 = array1(digits_sep(ind1)==1)
Code run -
array1 =
-94341 1234 4321 6515 847251737 6218473 541846 3115473 175846
output1 =
-94341 1234 4321 6515 847251737 6218473 541846 3115473 175846
output2 =
6515 6218473 541846 3115473
I have a file in the following format in matlab:
user_id_a: (item_1,rating),(item_2,rating),...(item_n,rating)
user_id_b: (item_25,rating),(item_50,rating),...(item_x,rating)
....
....
so each line has values separated by a colon where the value to the left of the colon is a number representing user_id and the values to the right are tuples of item_ids (also numbers) and rating (numbers not floats).
I would like to read this data into a matlab cell array or better yet ultimately convert it into a sparse matrix wherein the user_id represents the row index, and the item_id represents the column index and store the corresponding rating in that array index. (This would work as I know a-priori the number of users and items in my universe so ids cannot be greater than that ).
Any help would be appreciated.
I have thus far tried the textscan function as follows:
c = textscan(f,'%d %s','delimiter',':') %this creates two cells one with all the user_ids
%and another with all the remaining string values.
Now if I try to do something like str2mat(c{2}), it works but it stores the '(' and ')' characters also in the matrix. I would like to store a sparse matrix in the fashion that I described above.
I am fairly new to matlab and would appreciate any help regarding this matter.
f = fopen('data.txt','rt'); %// data file. Open as text ('t')
str = textscan(f,'%s'); %// gives a cell which contains a cell array of strings
str = str{1}; %// cell array of strings
r = str(1:2:end);
r = cellfun(#(s) str2num(s(1:end-1)), r); %// rows; numeric vector
pairs = str(2:2:end);
pairs = regexprep(pairs,'[(,)]',' ');
pairs = cellfun(#(s) str2num(s(1:end-1)), pairs, 'uni', 0);
%// pairs; cell array of numeric vectors
cols = cellfun(#(x) x(1:2:end), pairs, 'uni', 0);
%// columns; cell array of numeric vectors
vals = cellfun(#(x) x(2:2:end), pairs, 'uni', 0);
%// values; cell array of numeric vectors
rows = arrayfun(#(n) repmat(r(n),1,numel(cols{n})), 1:numel(r), 'uni', 0);
%// rows repeated to match cols; cell array of numeric vectors
matrix = sparse([rows{:}], [cols{:}], [vals{:}]);
%// concat rows, cols and vals into vectors and use as inputs to sparse
For the example file
1: (1,3),(2,4),(3,5)
10: (1,1),(2,2)
this gives the following sparse matrix:
matrix =
(1,1) 3
(10,1) 1
(1,2) 4
(10,2) 2
(1,3) 5
I think newer versions of Matlab have a stringsplit function that makes this approach overkill, but the following works, if not quickly. It splits the file into userid's and "other stuff" as you show, initializes a large empty matrix, and then iterates through the other stuff, breaking it apart and placing in the correct place in the matrix.
(I Didn't see the previous answer when I opened this for some reason - it is more sophisticated than this one, though this may be a little easier to follow at the expense of slowness). I throw in the \s* into the regex in case the spacing is inconsistent, but otherwise don't perform much in the way of data-sanity-checking. Output is the full array, that you can then turn into a sparse array if desired.
% matlab_test.txt:
% 101: (1,42),(2,65),(5,0)
% 102: (25,78),(50,12),(6,143),(2,123)
% 103: (23,6),(56,3)
clear all;
fclose('all');
% your path will vary, of course
file = '<path>/matlab_test.txt';
f = fopen(file);
c = textscan(f,'%d %s','delimiter',':');
celldisp(c)
uids = c{1}
tuples = c{2}
% These are stated as known
num_users = 3;
num_items = 40;
desired_array = zeros(num_users, num_items);
expression = '\((\d+)\s*,\s*(\d+)\)'
% Assuming length(tuples) == num_users for simplicity
for k = 1:num_users
uid = uids(k)
tokens = regexp(tuples{k}, expression, 'tokens');
for l = 1:length(tokens)
item_id = str2num(tokens{l}{1})
rating = str2num(tokens{l}{2})
desired_array(uid, item_id) = rating;
end
end