My English is not good, so please forgive me if what I describle is not clear for you.
I want to create 2 dimension Array with 0 and 1
when I input n, it should create: Array01(1 to 2^n as long, n as long), and 0 and 1 is combination like this:
n = 1 ==> Arr (2 rows x 1 column)
0 |
1 |
n = 2 ==> Arr (4 rows x 2 columns)
0 0 |
0 1 |
1 0 |
1 1 |
n = 3 ==> Array (8 rows x 3 columns)
0 0 0 |
0 0 1 |
0 1 0 |
1 0 0 |
1 1 0 |
1 0 1 |
0 1 1 |
1 1 1 |
You can use a function like below
Option Explicit
Public Function CreateMatrix(ByVal n As Long) As Variant
Dim Matrix() As Long
ReDim Matrix(1 To 2 ^ n, 1 To n)
Dim i As Long
For i = 0 To 2 ^ n - 1
Dim BinaryString As String
BinaryString = DecToBin(i, n)
Dim c As Long
For c = 1 To n
Matrix(i + 1, c) = CLng(Mid$(BinaryString, c, 1))
Next c
Next i
CreateMatrix = Matrix
End Function
Public Function DecToBin(ByVal DecimalIn As Variant, Optional ByVal NumberOfBits As Variant) As String
Dim Result As String
DecimalIn = CDec(DecimalIn)
Do While DecimalIn <> 0
Result = Trim$(Str$(DecimalIn - 2 * Int(DecimalIn / 2))) & Result
DecimalIn = Int(DecimalIn / 2)
Loop
If Not IsMissing(NumberOfBits) Then
If Len(Result) > NumberOfBits Then
Result = "Error - Number too large for bit size"
Else
Result = Right$(String$(NumberOfBits, "0") & Result, NumberOfBits)
End If
End If
DecToBin = Result
End Function
and call it like
' generate the matrix
Dim MyMatrix() As Long
MyMatrix = CreateMatrix(n:=3)
' and write it to a sheet
Worksheets("Sheet1").Range("A1").Resize(UBound(MyMatrix, 1), UBound(MyMatrix, 2)).Value = MyMatrix
How does this work?
If we look at the matrix below we can see each row as a binary number that can be converted into a decimal number. So binary 000 is decimal 0, then binary 001 is decimal 1 and binary 010 is decimal 2 and so on:
0 0 0 | 'decimal 0
0 0 1 | 'decimal 1
0 1 0 | 'decimal 2
1 0 0 | 'decimal 3
1 1 0 | 'decimal 4
1 0 1 | 'decimal 5
0 1 1 | 'decimal 6
1 1 1 | 'decimal 7
So we know if we want to create that matrix we need to convert the decimal numbers 1 to 7 into binary numbers. Each of this binary numbers then represents one row of the matrix.
Since the only number to define the martix is n (in the example n = 3) we can use that to calculate the dimensions of the matrix:
rows: 2 ^ n (in the example 2^3 = 8)
columns: n
So we define a matrix of that size ReDim Matrix(1 To 2 ^ n, 1 To n).
Then we need to generatate the decimal numbers from 1 to 7 to be able to convert them into binaries. We do that with a loop: For i = 0 To 2 ^ n - 1 (in the example this means For i = 0 To 7).
In that loop we convert each decimal number i into a binary string of the length n. We do that using BinaryString = DecToBin(i, n).
Finally we just need to split that string into the columns of our matrix. Therefore we use another loop that loops through the characters of that BinaryString For c = 1 To n (which means start with character 1 until character n). And fill the matrix:
Matrix(i + 1, c) = CLng(Mid$(BinaryString, c, 1))
Here Mid$(BinaryString, c, 1) picks the character out of the string and CLng converts it into a Long number so it is numeric and writes it into the correct position of the matrix Matrix(i + 1, c).
Fanally we return that matix as result of our function CreateMatrix = Matrix.
This post is 10 months old. But I saw a new post by the OP which led me here, so I thought I'd share another solution.
This can be solved by formula instead of script.
Suppose in cell A1 of some sheet you place the number for n.
In some other cell (say, A3 or C1), you could use the following formula to generate the list in question:
=FILTER(TEXT(SEQUENCE(10^A1,1,0),REPT("0",A1)),NOT(REGEXMATCH(SEQUENCE(10^A1,1,0)&"","[2-9]")))
Essentially, this formula creates a SEQUENCE of all possible numbers between 0 and 10 to the nth, formatted to contain n digits; then it FILTERs out any elements of that sequence that contain any digits from 2 to 9 (i.e., anything other than elements containing only 1s and 0s).
Related
Consider the following data:
A = [-1 -1 -1 0 1 -1 -1 0 0 1 1 1 1 -1 1 0 1];
How can the size and appearance frequency of clusters in A (of similar neighbors) be calculated, preferably using MATLAB built in commands?
The result should read something like
s_plus = [1 2 3 4 5 ; 3 0 0 1 0]'; % accounts (1,1,1,1) and (1),(1),(1) which appear in A
s_zero = [1 2 3 4 5 ; 2 1 0 0 0]'; % accounts (0,0) and (0),(0) which appear in A
s_mins = [1 2 3 4 5 ; 1 1 1 0 0]'; % accounts (-1), (-1,-1) , and (-1,-1,-1)) which appear in A
in the above the first column indicates the cluster size and the second column is the appearance frequency.
You can use run length encoding to transform your input array into two arrays
The value of a group (or "run" of equal values)
The number of elements in that group
Then you can covert this into your desired output by checking when two conditions are true
The values array matches the value you want (-1,0,1)
The group size matches 1..5
This might sound a bit tricky but it's only a few lines of code, and should be relatively fast for even large arrays because the outputs are calculated from the "encoded" arrays which will be smaller than the input array.
Here is the code, see the comments for details:
A = [-1 -1 -1 0 1 -1 -1 0 0 1 1 1 1 -1 1 0 1]; % Example input
% Run length encoding step
idx = [ find( A(1:end-1) ~= A(2:end) ), numel(A) ]; % Find group start points
count = diff([0, idx]); % Find number of elements in each group
val = A( idx ); % Get value of each group
% Helper function to go from "val" and "count" to desired output format
% by checking value = target and group size matches 1 to 5, counting matching groups.
f = #(v) sum(val==v & count==(1:5).',2).';
% Create outputs
s_plus = f(1); % = [3 0 0 1 0]
s_zero = f(0); % = [2 1 0 0 0]
s_mins = f(-1); % = [1 1 1 0 0]
I have a given matrix H and I would like to unfold (expand) it to find a matrix B by following the method below :
Let H be a matrix of dimension m × n. Let x = gcd (m,n)
The matrix H is cut in two parts.
The cutting pattern being such that :
The "diagonal cut" is made by alternately moving c = n/x units to the right (we move c units to the right several times).
We alternately move c-b = m/x units down (i.e. b = (n-m)/x) (we move b units down several times).
After applying this "diagonal cut" of the matrix, we copy and paste the two parts repeatedly to obtain the matrix B.
Exemple : Let the matrix H of dimension m × n = 5 × 10 defined by :
1 0 1 1 1 0 1 1 0 0
0 1 1 0 0 1 1 0 1 1
1 1 0 1 1 1 0 1 0 0
0 1 1 0 1 0 1 0 1 1
1 0 0 1 0 1 0 1 1 1
Let's calculate x = gcd (m,n) = gcd (5,10) = 5,
Alternatively move to the right : c = n/x = 10/5 = 2,
Alternatively move down : b = (n-m)/x = (10-5)/5 = 1.
Diagonal cutting diagram : The matrix H is cut in two parts.
The cutting pattern is such that :
We move c = 2 units to the right several times c = 2 units to the right,
We repeatedly move c - b = 1 unit downwards.
We get :
After applying this "diagonal cut" of the matrix, we copy and paste the two parts repeatedly to obtain the matrix :
Remark : In the matrices X, X1 and X2 the dashes are zeros.
The resulting matrix B is (L is factor) :
Any suggestions?
This can be done by creating a logical mask with the cutting pattern, and then element-wise multiplying the input by the mask and by its negation. Repeating by L can be done with blkdiag.
H = [1 0 1 1 1 0 1 1 0 0
0 1 1 0 0 1 1 0 1 1
1 1 0 1 1 1 0 1 0 0
0 1 1 0 1 0 1 0 1 1
1 0 0 1 0 1 0 1 1 1];
L = 2;
[m, n] = size(H);
x = gcd(m, n);
c = n / x;
b = (n-m)/x;
mask = repelem(tril(true(m/b)), b, c);
A = [H.*mask; H.*~mask];
A = repmat({A}, L, 1);
B = blkdiag(A{:});
I have an array (say of 1s and 0s) and I want to find the index, i, for the first location where 1 appears n times in a row.
For example,
x = [0 0 1 0 1 1 1 0 0 0] ;
i = 5, for n = 3, as this is the first time '1' appears three times in a row.
Note: I want to find where 1 appears n times in a row so
i = find(x,n,'first');
is incorrect as this would give me the index of the first n 1s.
It is essentially a string search? eg findstr but with a vector.
You can do it with convolution as follows:
x = [0 0 1 0 1 1 1 0 0 0];
N = 3;
result = find(conv(x, ones(1,N), 'valid')==N, 1)
How it works
Convolve x with a vector of N ones and find the first time the result equals N. Convolution is computed with the 'valid' flag to avoid edge effects and thus obtain the correct value for the index.
Another answer that I have is to generate a buffer matrix where each row of this matrix is a neighbourhood of overlapping n elements of the array. Once you create this, index into your array and find the first row that has all 1s:
x = [0 0 1 0 1 1 1 0 0 0]; %// Example data
n = 3; %// How many times we look for duplication
%// Solution
ind = bsxfun(#plus, (1:numel(x)-n+1).', 0:n-1); %'
out = find(all(x(ind),2), 1);
The first line is a bit tricky. We use bsxfun to generate a matrix of size m x n where m is the total number of overlapping neighbourhoods while n is the size of the window you are searching for. This generates a matrix where the first row is enumerated from 1 to n, the second row is enumerated from 2 to n+1, up until the very end which is from numel(x)-n+1 to numel(x). Given n = 3, we have:
>> ind
ind =
1 2 3
2 3 4
3 4 5
4 5 6
5 6 7
6 7 8
7 8 9
8 9 10
These are indices which we will use to index into our array x, and for your example it generates the following buffer matrix when we directly index into x:
>> x = [0 0 1 0 1 1 1 0 0 0];
>> x(ind)
ans =
0 0 1
0 1 0
1 0 1
0 1 1
1 1 1
1 1 0
1 0 0
0 0 0
Each row is an overlapping neighbourhood of n elements. We finally end by searching for the first row that gives us all 1s. This is done by using all and searching over every row independently with the 2 as the second parameter. all produces true if every element in a row is non-zero, or 1 in our case. We then combine with find to determine the first non-zero location that satisfies this constraint... and so:
>> out = find(all(x(ind), 2), 1)
out =
5
This tells us that the fifth location of x is where the beginning of this duplication occurs n times.
Based on Rayryeng's approach you can loop this as well. This will definitely be slower for short array sizes, but for very large array sizes this doesn't calculate every possibility, but stops as soon as the first match is found and thus will be faster. You could even use an if statement based on the initial array length to choose whether to use the bsxfun or the for loop. Note also that for loops are rather fast since the latest MATLAB engine update.
x = [0 0 1 0 1 1 1 0 0 0]; %// Example data
n = 3; %// How many times we look for duplication
for idx = 1:numel(x)-n
if all(x(idx:idx+n-1))
break
end
end
Additionally, this can be used to find the a first occurrences:
x = [0 0 1 0 1 1 1 0 0 0 0 0 1 0 1 1 1 0 0 0 0 0 1 0 1 1 1 0 0 0]; %// Example data
n = 3; %// How many times we look for duplication
a = 2; %// number of desired matches
collect(1,a)=0; %// initialise output
kk = 1; %// initialise counter
for idx = 1:numel(x)-n
if all(x(idx:idx+n-1))
collect(kk) = idx;
if kk == a
break
end
kk = kk+1;
end
end
Which does the same but shuts down after a matches have been found. Again, this approach is only useful if your array is large.
Seeing you commented whether you can find the last occurrence: yes. Same trick as before, just run the loop backwards:
for idx = numel(x)-n:-1:1
if all(x(idx:idx+n-1))
break
end
end
One possibility with looping:
i = 0;
n = 3;
for idx = n : length(x)
idx_true = 1;
for sub_idx = (idx - n + 1) : idx
idx_true = idx_true & (x(sub_idx));
end
if(idx_true)
i = idx - n + 1;
break
end
end
if (i == 0)
disp('No index found.')
else
disp(i)
end
I have an array that looks something like...
1 0 0 1 2 2 1 1 2 1 0
2 1 0 0 0 1 1 0 0 2 1
1 2 2 1 1 1 2 0 0 1 0
0 0 0 1 2 1 1 2 0 1 2
however my real array is (50x50).
I am relatively new to MATLAB and need to be able to count the amount of unique values in each row and column, for example there is four '1's in row-2 and three '0's in column-3. I need to be able to do this with my real array.
It would help even more if these quantities of unique values were in arrays of their own also.
PLEASE use simple language, or else i will get lost, for example if representing an array, don't call it x, but perhaps column_occurances_array... for me please :)
What I would do is iterate over each row of your matrix and calculate a histogram of occurrences for each row. Use histc to calculate the occurrences of each row. The thing that is nice about histc is that you are able to specify where the bins are to start accumulating. These correspond to the unique entries for each row of your matrix. As such, use unique to compute these unique entries.
Now, I would use arrayfun to iterate over all of your rows in your matrix, and this will produce a cell array. Each element in this cell array will give you the counts for each unique value for each row. Therefore, assuming your matrix of values is stored in A, you would simply do:
vals = arrayfun(#(x) [unique(A(x,:)); histc(A(x,:), unique(A(x,:)))], 1:size(A,1), 'uni', 0);
Now, if we want to display all of our counts, use celldisp. Using your example, and with the above code combined with celldisp, this is what I get:
vals{1} =
0 1 2
3 5 3
vals{2} =
0 1 2
5 4 2
vals{3} =
0 1 2
3 5 3
vals{4} =
0 1 2
4 4 3
What the above display is saying is that for the first row, you have 3 zeros, 5 ones and 3 twos. The second row has 5 zeros, 4 ones and 2 twos and so on. These are just for the rows. If you want to do these for columns, you have to modify your code slightly to operate along columns:
vals = arrayfun(#(x) [unique(A(:,x)) histc(A(:,x), unique(A(:,x)))].', 1:size(A,2), 'uni', 0);
By using celldisp, this is what we get:
vals{1} =
0 1 2
1 2 1
vals{2} =
0 1 2
2 1 1
vals{3} =
0 2
3 1
vals{4} =
0 1
1 3
vals{5} =
0 1 2
1 1 2
vals{6} =
1 2
3 1
vals{7} =
1 2
3 1
vals{8} =
0 1 2
2 1 1
vals{9} =
0 2
3 1
vals{10} =
1 2
3 1
vals{11} =
0 1 2
2 1 1
This means that in the first column, we see 1 zero, 2 ones and 1 two, etc. etc.
I absolutely agree with rayryeng! However, here is some code which might be easier to understand for you as a beginner. It is without cell arrays or arrayfuns and quite self-explanatory:
%% initialize your array randomly for demonstration:
numRows = 50;
numCols = 50;
yourArray = round(10*rand(numRows,numCols));
%% do some stuff of what you are asking for
% find all occuring numbers in yourArray
occVals = unique(yourArray(:));
% now you could sort them just for convinience
occVals = sort(occVals);
% now we could create a matrix occMat_row of dimension |occVals| x numRows
% where occMat_row(i,j) represents how often the ith value occurs in the
% jth row, analoguesly occMat_col:
occMat_row = zeros(length(occVals),numRows);
occMat_col = zeros(length(occVals),numCols);
for k = 1:length(occVals)
occMat_row(k,:) = sum(yourArray == occVals(k),2)';
occMat_col(k,:) = sum(yourArray == occVals(k),1);
end
If I have sequence 1 0 0 0 1 0 1 0 1 1 1
how to effectively locate zero which has from both sides 1.
In this sequence it means zero on position 6 and 8. The ones in bold.
1 0 0 0 1 0 1 0 1 1 1
I can imagine algorithm that would loop through the array and look one in back and one in front I guess that means O(n) so probably there is not any more smooth one.
If you can find another way, I am interested.
Use strfind:
pos = strfind(X(:)', [1 0 1]) + 1
Note that this will work only when X is a vector.
Example
X = [1 0 0 0 1 0 1 0 1 1 1 ];
pos = strfind(X(:)', [1 0 1]) + 1
The result:
pos =
6 8
The strfind method that #EitanT suggested is quite nice. Another way to do this is to use find and element-wise bit operations:
% let A be a logical ROW array
B = ~A & [A(2:end),false] & [false,A(1:end-1)];
elements = find(B);
This assumes, based on your example, that you want to exclude boundary elements. The concatenations [A(2:end),false] and [false,A(1:end-1)] are required to keep the array length the same. If memory is a concern, these can be eliminated:
% NB: this will work for both ROW and COLUMN vectors
B = ~A(2:end-1) & A(3:end) & A(1:end-2);
elements = 1 + find(B); % need the 1+ because we cut off the first element above
...and to elaborate on #Eitan T 's answer, you can use strfind for an array if you loop by row
% let x = some matrix of 1's and 0's (any size)
[m n] = size(x);
for r = 1:m;
pos(r,:) = strfind(x(r,:)',[1 0 1]) + 1;
end
pos would be a m x ? matrix with m rows and any returned positions. If there were no zeros in the proper positions though, you might get a NaN ... or an error. Didn't get a chance to test.