I have a text file with format
2..4..6.7
.1.2.3.5.
34.7..89.
Desired output:
A = 3x9 cell
1x9 double: 200400607
1x9 double: 010203040
1x9 double: 340700890
I can read the file like this
importdata('inputname.txt')
but then they are still arrays of type char and not of type double.
How do I replace chars with numbers?
Use the importdata option that you had before:
data = importdata('inputname.txt');
Now, you can just replace all of the . characters with 0 via string operations. Use strrep to do that:
data = strrep(data, '.', '0');
We get:
data =
'200400607'
'010203050'
'340700890'
Some older versions of MATLAB don't have strrep. If you don't, then use regular expressions via regexprep to do that for you:
data = regexprep(data, '\.', '0');
Now, the last task is to convert each of the cells into individual digits, you can use cellfun and loop over each cell, and subtract each character array by the ASCII code of 0 to get your desired numeric array. This will be type converted to a double array and by subtracting the ASCII code of 0, you will get digits between 0 and 9:
data = cellfun(#(x) x - '0', data, 'uni', 0);
We get:
>> celldisp(data)
data{1} =
2 0 0 4 0 0 6 0 7
data{2} =
0 1 0 2 0 3 0 5 0
data{3} =
3 4 0 7 0 0 8 9 0
However, if you want the actual full number itself rather than splitting it up into characters, just use str2double instead:
data = cellfun(#str2double, data);
You would get:
>> data
data =
200400607
10203050
340700890
Take note that the above will remove any leading zeroes you have for each number, which makes sense as those don't add anything meaningful to the interpretation of the number.
Related
I'm currently trying to export multiple matrices of unequal lengths into a delimited .txt file thus I have been padding the shorter matrices with 0's such that dlmwrite can use horzcat without error:
dlmwrite(filename{1},[a,b],'delimiter','\t')
However ideally I do not want the zeroes to appear in the .txt file itself - but rather the entries are left blank.
Currently the .txt file looks like this:
55875 3.1043e+05
56807 3.3361e+05
57760 3.8235e+05
58823 4.2869e+05
59913 4.3349e+05
60887 0
61825 0
62785 0
63942 0
65159 0
66304 0
67509 0
68683 0
69736 0
70782 0
But I want it to look like this:
55875 3.1043e+05
56807 3.3361e+05
57760 3.8235e+05
58823 4.2869e+05
59913 4.3349e+05
60887
61825
62785
63942
65159
66304
67509
68683
69736
70782
Is there anyway I can do this? Is there an alternative to dlmwrite which will mean I do not need to have matrices of equal lengths?
If a is always longer than b you could split vector a into two vectors of same length as vector b and the rest:
a = [1 2 3 4 5 6 7 8]';
b = [9 8 7 ]';
len = numel(b);
dlmwrite( 'foobar.txt', [a(1:len), b ], 'delimiter', '\t' );
dlmwrite( 'foobar.txt', a(len+1:end), 'delimiter', '\t', '-append');
You can read in the numeric data and convert to string and then add proper whitespaces to have the final output as string based cell array, which you can easily write into the output text file.
Stage 1: Get the cell of strings corresponding to the numeric data from column vector inputs a, b, c and so on -
%// Concatenate all arrays into a cell array with numeric data
A = [{a} {b} {c}] %// Edit this to add more columns
%// Create a "regular" 2D shaped cell array to store the cells from A
lens = cellfun('length',A)
max_lens = max(lens)
A_reg = cell(max_lens,numel(lens))
A_reg(:) = {''}
A_reg(bsxfun(#le,[1:max_lens]',lens)) = cellstr(num2str(vertcat(A{:}))) %//'
%// Create a char array that has string data from input arrays as strings
wsp = repmat({' '},max_lens,1) %// Create whitespace cell array
out_char = [];
for iter = 1:numel(A)
out_char = [out_char char(A_reg(:,iter)) char(wsp)]
end
out_cell = cellstr(out_char)
Stage 2: Now, that you have out_cell as the cell array that has the strings to be written to the text file, you have two options next for the writing operation itself.
Option 1 -
dlmwrite('results.txt',out_cell(:),'delimiter','')
Option 2 -
outfile = 'results.txt';
fid = fopen(outfile,'w');
for row = 1:numel(out_cell)
fprintf(fid,'%s\n',out_cell{row});
end
fclose(fid);
Say I have matrices A and B. I want to create a third matrix C where
A = [1,0,0,1]
B = [1,0,1,0]
C = [11, 00, 01, 10]
Is there such a function in Matlab? If not how would I go about creating a function that does this?
Edit: C is not literal numbers. They are concatenated values of A,B element-wise.
Edit2: The actual problem I am dealing with is I have 10 large matrices of the size [x,y] where x,y > 1000. The elements in these matrices all have 0s and 1s. No other number. What I need to accomplish is have the element [x1,y1] in matrix 1 to be appended to the element in [x1,y1] of matrix 2. and then that value to be appended to [x1,y1] of matrix 3.
Another example:
A = [1,1,1,1;
0,0,0,0]
B = [0,0,0,0;
1,1,1,1]
C = [1,0,1,0;
0,1,0,1]
And I need a matrix D where
D = [101, 100, 101, 101; 010, 011, 010, 011]
I recommend that you avoid manipulating binary numbers as strings where possible. It seems tempting, and there are cases where matlab provides a more elegant solution if you treat a binary number as a string, but you cannot perform binary arithmetic on strings. You can always work with integers as if they were binary (they are stored as bits in your machine after all), and then just display them as binary numbers using dec2bin when necessary.
A = [1,0,0,1]
B = [1,0,1,0]
C = bitshift(A,1)+B;
display(dec2bin(C));
In the other case you show in your question you could use:
A = [1,1,1,1; 0,0,0,0];
B = [0,0,0,0; 1,1,1,1];
C = [1,0,1,0; 0,1,0,1];
D = bitshift(A,2) + bitshift(B,1) + C;
You can also convert an arbitrary length row vector of zeros and ones into its decimal equivalent by defining this simple function:
mat2dec = #(x) x*2.^(size(x,2)-1:-1:0)';
This will also work for matrices too. For example
>> M = [0 0 1; 0 1 1; 0 1 0; 1 1 0; 1 1 1; 1 1 0; 1 0 0];
>> dec2bin(mat2dec(M))
ans =
001
011
010
110
111
110
100
In my experience, treating binary numbers as strings obfuscates your code and is not very flexible. For example, try adding two binary "strings" together. You have to use bin2dec every time, so why not just leave the numbers as numbers until you want to display them? You have already run into some of the issues caused by strings of different lengths too. You will be amazed how one simple change can break everything when treating numbers as strings. The worst part is that an algorithm may work great for one set of data and not for another. If all I test with is two-bit binary numbers and a three-bit number somehow sneaks its way in, I may not see an error, but my results will be inexplicably incorrect. I realize that this is a very subjective issue, and I think that I definitely stand in the minority on StackOverflow, so take it for what it's worth.
It depends how you want the output formatted. You could apply bitshift to the numerical values and convert to binary:
>> b = dec2bin(bitshift(A,1)+B)
b =
11
00
01
10
For a general matrix Digits:
>> Digits
Digits =
1 0 0 0
0 1 0 0
1 0 1 1
1 1 0 0
1 0 0 0
1 0 1 1
1 1 0 0
1 0 1 0
0 1 1 1
0 1 1 1
>> Ddec = D*(2.^(size(D,2)-1:-1:0))'; % dot product
>> dec2bin(Ddec)
ans =
1000
0100
1011
1100
1000
1011
1100
1010
0111
0111
Another way to write that is dec2bin(sum(D .* repmat(2.^(size(D,2)-1:-1:0),size(D,1),1),2)).
For your larger problem, with 10 large matrixes (say M1, M2, ..., M10), you can build the starting Digits matrix by:
Digits = [M1(:) M2(:) M3(:) M4(:) M5(:) M6(:) M7(:) M8(:) M9(:) M10(:)];
If that is reverse the order of the digits, just do Digits = fliplr(Digits);.
If you would rather not reshape anything you can compute the matrix decimal values from the matrices of digits as follows:
M = cat(3,A,B,C);
Ddec = sum(bsxfun(#times,M,permute(2.^(size(M,3)-1:-1:0),[1 3 2])),3)
I see some quite extensive answers so perhaps this is thinking too simple, but how about just this assuming you have vectors of ones and zeros representing your binary numbers:
A = [1,0,0,1];
B = [1,0,1,0];
C = 10*A + B
This should give you the numbers you want, you may want to add leading zeros. Of course this method can easily be expanded to append multiple matrices, you just need to make sure there is a factor (base) 10 between them before adding.
This is how I do it with arrays where binaries are stored
>> hhh=[1 0 1 0 1 0 0; 0 0 1 0 0 0 0; 1 0 1 0 0 0 0; 0 0 0 1 1 0 1]; find(hhh(:,1)==1)
ans =
1
3
and now I am trying to understand how to do it with binary numbers
>> hhhh=[1010100; 0010000; 1010000; 0001101]; find(hhhh(:,1)==1)
ans =
Empty matrix: 0-by-1
where the hack to break up all binaries back into arrays can work (ismember('101010','1') and then prepending with zeros) but I feel there is probably some better alternative so
By which command to check whether Nth bit active in binary number?
P.s. Harder puzzle: is there a type-agnostic solution that would work with both binaries and DEC?
String Input
If you have a string input, you can get away with testing for char equality:
find(hhh(:, 1) == '1')
for string arrays (i.e char matrices), you can extract both outputs of find (rows and columns) to be able to determine which active bit corresponds to which string:
[r, c] = find(hhh == '1');
Numeric Input
For numeric inputs, you can use bitget to get the binary representation. From there, it's very similar to the solution for string inputs:
B = bsxfun(#bitget, hhh, size(hhh, 1):-1:1);
[r, c] = find(B);
Note that find searches for non-zero elements, so there's no need to write find(B == 1) explicitly.
Combined Solution
If the solution for the "harder puzzle" is what you're after, you can determine the type of the input first, and handle it accordingly:
if ischar(hhh)
%// Apply solution to string array
%//...
else if isnumeric(hhh)
%// Apply solution to numeric input
%// ...
else
%// This type is unsupported
assert('Matrix is of unsupported type')
end
Repeating my comment in form of an answer:
There's no need to work with the string/array-like representation of the bits in this case.
You can use bitget right on the output of find(mlf). Like:
filled = find(mlf);
filled_and_bit2 = filled(logical(bitget(filled,2)));
You should store your binary number as a string matrix:
hhhh=['1010100'; '0010000'; '1010000'; '0001101'];
Then you can do
find(bin2dec(hhhh) >= bin2dec('1000000'))
returns:
ans =
1
3
or you could use the less intuitive (but probably faster)
find(hhhh(:,1)-'0') %// Or find(hhhh(:,1)=='1') as EitanT points out
to get the same result.
This is not a direct answer to the question but related -- good point by Sebastian in a comment! So suppose that the binaries are indices. Now instead of playing with dec2bin something like
>> hhh=dec2bin(find(mlf));B=bsxfun(#bitget, hhh, 8:-1:1);find(B)
Error using bsxfun
Non-singleton dimensions of the two input arrays must match each other.
we can directly address the indices like
>> filled = find(mlf);
filled_and_bit2 = bitget(filled,1);
filled(logical(filled_and_bit2))
ans =
1
7
where it finds the binaries with the first active bit.
Procedure
Data
>> mlf=sparse([],[],[],2^31,1);
mlf(1)=7;
mlf(4)=10;
mlf(7)=-1;
>> mlf
mlf =
(1,1) 7
(4,1) 10
(7,1) -1
>> find(mlf)
ans =
1
4
7
Interpret the index numbers as binary
(1,1) -----> 000001
(4,1) -----> 000100
(7,1) -----> 000111
Examples
Output 1: find cases where 3th bit is active
4
7
Output: find cases where 1st bit is active
1
7
Output: find cases where 2nd bit is active
4
So basically this is what I want to do:
I have the decimal value 3 as such:
x=3
Now i get the binary format as such:
s = dec2bin(x,3)
s = 011
The format of s is a string (correct?).
Now I would like to convert this value to a matrix, in order to do matrix operations on it. As such:
A = [0 1 1]
But I cannot seem to get this right. I have tried both str2mat and cell2mat but no results. Any ideas?
If you are 100% certain you will only be getting 0s and 1s, use:
a = '001';
b = double(a)-48;
(0 is 48 in ASCII)
Here's one way:
>> cellfun(#str2num, cellstr(s'))'
ans =
0 1 1
As you've noticed, MATLAB isn't that great for string manipulation. :)
You can as well do that:
x=3;
binNumber = dec2bin(x,3);
A=sprintf('%s',binNumber) - '0';
I need to convert logical vector to string .. so i can take each 8 bits of the logical vectors and convert it to it's equevilant of char ..
A=0 1 1 1 0 1 1 0 1 1 0 0 0 0 1 ;
A is of type logical
i need to convert it to a string , so A will equal 'va'
You can use char to convert a number to a character.
To convert each 8 elements of A into a number, there are a few methods:
% using definition of binary
n = sum(A(1:8).*2.^[7:-1:0])
% using 'base2dec'
n = base2dec(sprintf('%i',A(1:8)),2)
Then use char(n) to get the character out.
To apply this to every 8 elements of A you could use a loop or something like arrayfun.
arrayfun( #(i) char(base2dec(sprintf('%i',A(i:(i+7))),2)),
1:8:length(A) )
Note The A you gave in your original question has only 15 elements so you can't really group every 8 (need 16) - you will need to write some code to deal with what to do in this case.
Helpful docs:
base2dec
arrayfun
char
In addition to #mathematical.coffee answer, instead of SPRINTF you can simply add 48 (which is code for character '0') to A to get the string:
Astr = char(A + 48);
or
Astr = char(A + int8('0'));
You can also use BIN2DEC instead of BASE2DEC.
So you can use it in ARRAYFUN as
arrayfun( #(i) char(bin2dec(char(A(i:(i+7))+48))),1:7:length(A) )