I have a matrix in MATLAB as follows:
A = [ 0, 0, 0;
1, 2, 3;
4, 2, 3;
0, 0, 0;
1, 3, 4 ];
I would like to remove the zeros from line 1 and line 4 so I can get the following matrix:
B = [ 1, 2, 3;
4, 2, 3;
1, 3, 4 ];
What I did is the following:
for i = 1:length(A)
if (sum(A(i, :)) == 0)
A(i, :) = [];
end
end
I know that the problem is that A is changing in the size so that is the problem. Unfortunately, I cannot fix it. Could you please give me some hint.
If you want to remove the rows with zero sum this might help,
A(sum(A,2)==0,:)=[];
As mentioned by #LuisMendo you can use
A(all(A,2)==0,:)=[];
depending on what criteria you have in mind.
Kamtal's approach would work assuming that you have no rows that summed to zero. To be safer, you should check to see if a row consists only of zeroes. In other words, try doing this:
A(~any(A,2), :) = [];
any checks to see if an array or matrix has any of its elements to be non-zero which outputs logical true and false otherwise. If you use any over a matrix, you can specify whether you want to check for this over the rows or the columns in the second parameter of any. In your case, you want to operate over the columns for each row, and so you'd specify the second parameter to be 2.
Because you want to check to see if any row consists of all zeroes, you would use any over the columns and check for the reverse. As such, any would output logical false if all of a row consisted only of zeroes. This is what we're looking for, but you want this to be true and not false, and hence we invert using ~ as the opposite is what we seek.
However, if you want to get your method working, you would not use a for loop, but a while loop instead as the index to access each row keeps changing. As such, once you remove a row, you would not increment the index to access the next row, until you successfully find a row which doesn't sum to zero. Remember, as you remove a row, the row that was just below it gets moved to the position that was removed, and so you would still check this same position for a row that didn't sum to zero. You would move to the next row once you find a row that didn't sum to zero.
In other words, do this:
i = 1;
while i < length(A)
if (sum(A(i, :)) == 0)
A(i, :) = [];
continue;
end
i = i + 1;
end
Related
My task is to grab a 2-dimensional table from cells on a worksheet into a 2-dimensional array, delete some or all of the rows (right terminology?) from testing, and then paste what's left into a worksheet.
To determine the range for pasting I need to know the length of the edited array. This is where I'm challenged.
// This gets the array which is 3 columns wide and X rows (X will vary)
var termEmp = spreadsheet.getRangeByName("roeList").getValues();
// e.g. termEmp = [ ["Bob", 1, "day", "key"] ["Cindy", 2, "day", "it"] ["Laura", 1, "night", "we"] ]
// Then I find the number of rows that actually have data
numRows = termEmp[0].length; // result = 3
// A for loop with counter i tests if the second element equals 2 of each row and deletes each array row if it's there
// In this example I want to delete the row with Cindy because of the 2
// To do this is use the splice method to delete the second row thusly:
termEmp.splice(i,1); // i = 1 in the for loop
// After testing all elements, and deleting the rows I want, I then need to count the number of rows remaining (to create a range for pasting into the worksheet)
numRows = termEmp[0].length;
// This is SUPPOSED to count the number of rows remaining (first element is ALWAYS non-blank)
Here's my problem. For this example the number of rows after the splice goes from 3 to 2. I looked at the array to confirm this.
But in my code termEmp[0].length STAYS at 3. I can't use it to define my range for pasting.
What's needed to get the count right?
For number of rows, you can get the length of the full array.
var numRows = termEmp.length
What you're getting with termEmp[0].length is the number of columns in first row.
EDIT
OP indicated the answer "doesn't work" (which is false) however, as a courtesy here's subsequent code that helps his followup question to identify members in an array contain another array (effectively 2-dimensional spreadsheet data). The below code will take all memembers from termEmp that are an array, and inserts them into cleanedArray.
var cleanedArray = [];
for(var i=0;i<termEmp.length;i++){
var singleMember = termEmp[i];
if(Array.isArray(singleMember)){
//makes a clean array with only 2d values
cleanedArray.push(singleMember);
}
}
var numberOfMembers = cleanedArray.length;
Logger.log(numberOfMembers);
I am new to Matlab and thus this could be a very trivial question and I appreciate those who take the time to help. I have a 618x2 matrix that has values in the first column and then the index of the value (circles on an image for this case). For example
46.9810, 1
0, 2
0, 3
0, 4
43.1429, 5
0, 6
0, 7...
This matrix is called 'Test2'
I have another matrix that is a 1x58 matrix (called overlapindex) The values in this matrix correspond to the index in the 'Test2' matrix
for example:
1, 3, 5, 7, 35, 37, 44, 49,....
I need a new matrix (let's call it NEW) that checks if the value in overlapindex has a nonzero correlating value in the 'Test2' matrix. For example, this NEW matrix would include [43.1429, 5] because the index is in both 'Test2' and also in 'overlapindex' and the corresponding value in 'Test2' is nonzero.
so essentially this 'NEW' matrix would look like...
46.9810, 1
43.1429, 5
and so on until all the indexes are checked and the 'NEW' matrix is made.
I just need to make sure that the index in 'overlapindex' corresponds to an actual non zero value in the 'Test2' matrix.
Please help and thank you in advance!
Your problem can be solved using logical indexing in Matlab:
NEW = Test2(overlapindex(Test2(overlapindex, 1) ~= 0), :)
Explanation
Test2(overlapindex, 1): rows which should be checked (accessing Nonconsecutive Elements)
Test2(overlapindex, 1) ~= 0: checks for every requested row if the condition is true
overlapindex(Test2(overlapindex, 1) ~= 0): indexes of the matched rows (logical indexing)
Note that this solution only works if overlapindex only contains existing indexes of Test2, but the solution could be easily extended to skip non-existing indexes.
I have the 137x19 cell array Location(1,4).loc and I want to find the number of times that horizontal consecutive values are present in Location(1,4).loc. I have used this code:
x=Location(1,4).loc;
y={x(:,1),x(:,2)};
for ii=1:137
cnt(ii,1)=sum(strcmp(x(:,1),y{1,1}{ii,1})&strcmp(x(:,2),y{1,2}{ii,1}));
end
y={x(:,1),x(:,2),x(:,3)};
for ii=1:137
cnt(ii,2)=sum(strcmp(x(:,1),y{1,1}{ii,1})&strcmp(x(:,2),y{1,2}{ii,1})&strcmp(x(:,3),y{1,3}{ii,1}));
end
y={x(:,1),x(:,2),x(:,3),x(:,4)};
for ii=1:137
cnt(ii,3)=sum(strcmp(x(:,1),y{1,1}{ii,1})&strcmp(x(:,2),y{1,2}{ii,1})&strcmp(x(:,3),y{1,3}{ii,1})&strcmp(x(:,4),y{1,4}{ii,1}));
end
y={x(:,1),x(:,2),x(:,3),x(:,4),x(:,5)};
for ii=1:137
cnt(ii,4)=sum(strcmp(x(:,1),y{1,1}{ii,1})&strcmp(x(:,2),y{1,2}{ii,1})&strcmp(x(:,3),y{1,3}{ii,1})&strcmp(x(:,4),y{1,4}{ii,1})&strcmp(x(:,5),y{1,5}{ii,1}));
end
... continue for all the columns. This code run and gives me the correct result but it's not automated and it's slow. Can you give me ideas to automate and speed up the code?
I think I will write an answer to this since I've not done so for a while.
First convert your cell Array to a matrix,this will ease the following steps by a lot. Then diff is the way to go
A = randi(5,[137,19]);
DiffA = diff(A')'; %// Diff creates a matrix that is 136 by 19, where each consecutive value is subtracted by its previous value.
So a 0 in DiffA would represent 2 consecutive numbers in A are equal, 2 consecutive 0s would mean 3 consecutive numbers in A are equal.
idx = DiffA==0;
cnt(:,1) = sum(idx,2);
To do 3 consecutive number counts, you could do something like:
idx2 = abs(DiffA(:,1:end-1))+abs(DiffA(:,2:end)) == 0;
cnt(:,2) = sum(idx2,2);
Or use another Diff, the abs is used to avoid negative number + positive number that also happens to give 0; otherwise only 0 + 0 will give you a 0; you can now continue this pattern by doing:
idx3 = abs(DiffA(:,1:end-2))+abs(DiffA(:,2:end-1))+abs(DiffA(:,3:end)) == 0
cnt(:,3) = sum(idx3,2);
In loop format:
absDiffA = abs(DiffA)
for ii = 1:W
absDiffA = abs(absDiffA(:,1:end-1) + absDiffA(:,1+1:end));
idx = (absDiffA == 0);
cnt(:,ii) = sum(idx,2);
end
NOTE: this method counts [0,0,0] twice when evaluating 2 consecutives, and once when evaluating 3 consecutives.
Suppose I have an array of length N. I want to choose n positions randomly, make them zero and then add the existing elements to the next non-zero element.
For example, suppose r = (r1,r2,r3,r4,r5), N = 5. Let n = 2. And the randomly picked positions are 3rd and 4th. Then I want to transform r to
r_new = (r1, r2, 0, 0, r3+r4+r5).
Instead if the randomly selected positions were 1 and 3, then I want to have
r_new = (0, r1 + r2, 0, r3+r4, r5).
I am coding in MATLAB. Here is my current code.
u = randperm(T);
ind = sort(u(1:n(i)));
tmp = r(ind);
r(ind) = 0;
x = find( r );
I am not necessarily looking for MATLAB code. Pseudocode would be helpful enough.
I'm assuming the last position can never be selected, otherwise the intended behaviour is undefined. So you randomly select n positions uniformly distributed from 1 up to N-1 (not up to N).
Here's one approach:
Select n distinct random positions from 1 to N-1, and sort them. Call the resulting vector of positions pos. This can be easily done with randperm and sort.
For each value in pos, say p, accumulate r(p) into r(p+1), and set r(p) to zero. This is done with a for loop.
In step 2, if position p+1 happens to belong to pos too, the accumulated value will be moved further to the right in a subsequent iteration. This works because pos has been sorted, so the randomly selected positions are processed from left to right.
r = [3 5 4 3 7 2 8]; %// data
n = 2; %// number of positions
pos = sort(randperm(numel(r)-1,n)); %// randomly select positions, and sort them
for p = pos
r([p p+1]) = [0 r(p)+r(p+1)]; %// process position p
end
Assuming N, n and r are already generated, then we select random indexes:
inds = randi(N,n,1);
Then to achieve the desired results you can loop as follows:
inds = sort(inds);
for ii=1:numel(inds)
if(inds(ii)<N)
r(inds(ii)+1)=r(inds(ii)+1) +r(inds(ii));
r(inds)=0;
else
r(inds)=0;
end
end
This will create the desired outcome of adding the values to the next index that wasn't selected to be set to 0.
Note I had to assume an edge case where if the last index is set to 0, then its value is not added to anything.
I have a 2 dimensional array which randomly contains values of 0 or 1.
How can I ( most efficiently ) determine the lower most element of value 1 ( the biggest row iteration i ) and the right most element ( the highest column iteration j ) ?
For example:
0 0 1 0
1 0 1 0
0 1 0 0
1 0 0 0
My program should answer i = 3 ( assuming first row is i = 0) and j = 2 ( assuming first column is 0 ).
Here's an idea:
Starting with the bottom-most row, use memrchr to find the last 1 in each row (I'm sort of assuming you store the numbers as char aka 8-bit integers).
Eventually you will find a row which has a 1. This is your answer for i. We got this far using cache-friendly, row-at-a-time operations because C uses row-major order.
Above, you also now know the lower bound for j (because you found the last 1 in the last row that had any 1s).
For the remaining rows, use memrchr from one past the lower bound for j to the end of each row. If you find any 1s there, update the lower bound. Repeat until you have inspected all the rows.
Of course, if you ever find a 1 in the last column, you can stop right away.
Use a plain loop and simply search from the beginning (or the end, depending on what you want to achieve) and check each element. There is no more efficient way.
As far as C and C++ are concerned, what is efficient and what is not lies in the nature of the implementation. If this is a bit field matrix for example, then you can optimize the code slightly by first comparing each byte against 0, before you start searching through the individual bits.
And as usual, it doesn't make sense to talk about efficiency without specifying what it means. Speed? Memory consumption? Program size? It also doesn't make sense to talk about efficient implementation in C or C++ without a given system in mind.
Here is the naive method - just iterating through all positions in the array. Worst case O(n*m):
#define WIDTH 4
#define HEIGHT 4
int main ()
{
int i,j,col,row;
int arr[HEIGHT][WIDTH] = set_Array();
for (j=0;j<HEIGHT;j++){
for (i = 0; i<WIDTH; i++){
if (arr[j][i]){
row = j>row?j:row;
col = i>col?i:col;
}}}
}
How can we improve this? Well we can start from the end and work backwards, but we will have to do the rows and columns alternately rather than just visiting each cell in turn. We could look for column, and then row, but that would be less efficient.
0. 1. 2. 3.
0. 0 0 1 0
1. 1 0 1 0
2. 0 1 0 0
3. 1 0 0 0
In this example, we search row 3 and column 3 first, and eliminate them from the search. Then row 2 and column 2 up to but not including the eliminated column 3 and row 3. Then row 1...
Of course, we stop searching rows when the bottom most one containing a 1 is found, and stop searching columns when the rightmost one containing a 1 is found.
Code:
#include <stdio.h>
#define WIDTH 4
#define HEIGHT 4
int main ()
{
int i,j,col = 0, row = 0;
int current_row = HEIGHT;
int current_col = WIDTH;
int arr[WIDTH][HEIGHT] = {{0,0,1,0},{1,0,1,0},{0,1,0,0},{1,0,0,0}};
while (!(row && col))
{
current_row--;
current_col--;
if (!row){
printf("searching row: %d\n",current_row);
for (i = 0; i < current_col; i++){
if (arr[current_row][i]){
row = current_row;
}}}
if (!col){
printf("searching col: %d\n",current_col);
for (j = 0; j < current_row; j++){
if (arr[j][current_col]){
col = current_col;
}}}
}
printf("col: %d, row: %d\n", col, row);
}
See it live
Output:
searching row: 3
searching col: 3
searching col: 2
col: 2, row: 3
The worst case is still O(m*n), and is actually slightly worse (you test cells on the diagonal starting from the bottom right twice), but the average case is better.
We scan through the lowest unsearched row for a 1, then search through the rightmost unsearched column for a 1.
When you find the lowest 1 you no longer search each row for more 1's. When you find the rightmost 1 you no longer search each column for more 1's either.
This way we stop the search once we find the answer, and unlike the naive method, this means that we don't usually have to go through each value in the array.
If the row size of the array is up to 32 numbers you can use a single int32_t to represent a whole row: The value of the number is the whole row.
Then your whole array will be a one dimensional array of int32_t's:
int32_t matrix[nRows];
Now you can find the lowermost row by finding the last number of matrix that is not equal to 0 in O(nRows) time with a very simple implementation.
Also, you can find the rightmost 1 by with the following trick:
For each matrix[i] you isolate the rightmost 1 by calculating matrix[i] & -matrix[i]. Then calculating the log2 of this result gives you the number of the column. The largest number of column for all matrix[i] numbers gives you the result you want. (Again O(nRows) time with a very simple implementation).
Of course, if the row size is larger that 32 values, you have to use more int32_t values per row, but the principle remains the same.