I have an R list (docs) where its first 2 elements are as follows:
1. A. 1 2 5 6
B. 5 6 2
C. 7 8 1 2 3 5
2. A. 4 5 3
B. 1 2 3 5 4 7 8
What I want to achieve is another list with equal sizes but with zeros instead:
1. A. 0 0 0 0
B. 0 0 0
C. 0 0 0 0 0 0
2. A. 0 0 0
B. 0 0 0 0 0 0 0
I have tried:
sapply(docs, function(x) rep(0, length(x)))
but the behaviour is not the intended because it considers the size of the outer list. Could you please help me?
It appears that you have a list of lists, that is docs is a list containing the lists 1 and 2, which then contain numeric vectors. If this is the case, try the following:
# create test list
temp <- list("v1"=list("A"=1:4,"B"=5:7,"C"=1:8), "v2"=list("A"=1:3,"B"=5:10,"C"=3:8))
# get a list of zeros with the same dimension
answer <- lapply(temp, function(x) sapply(x, function(y) rep(0, length(y))))
Related
In MATLAB, there is the bwlabel function, that given a binary vector, for instance x=[1 1 0 0 0 1 1 0 0 1 1 1 0] gives (bwlabel(x)):
[1 1 0 0 0 2 2 0 0 3 3 3 0]
but what I want to obtain is
[1 1 2 2 2 3 3 4 4 5 5 5 6]
I know I can negate x to obtain (bwlabel(~x))
[0 0 1 1 1 0 0 2 2 0 0 0 3]
But how can I combine them?
All in one line:
y = cumsum([1,abs(diff(x))])
Namely, abs(diff(x)) spots changes in the binary vector, and you gain the output with the cumulative sum.
You can still do it using bwlabel by vertically concatenating x and ~x, using 4-connected components for the labeling, then taking the maximum down each column:
>> max(bwlabel([x; ~x], 4))
ans =
1 1 2 2 2 3 3 4 4 5 5 5 6
However, the solution from Bentoy13 is probably a bit faster.
x=[1 1 0 0 0 1 1 0 0 1 1 1 0];
A = bwlabel(x);
B = bwlabel(~x);
if x(1)==1
tmp = A>0;
A(tmp) = 2*A(tmp)-1;
tmp = B>0;
B(tmp) = 2*B(tmp);
C = A+B
elseif x(1)==0
tmp = A>0;
A(tmp) = 2*A(tmp);
tmp = B>1;
B(tmp) = 2*B(tmp)-1;
C = A+B
end
C =
1 1 2 2 2 3 3 4 4 5 5 5 6
You know the first index should remain 1, but the second index should go from 1 to 2, the third from 2 to 3 etc; thus even indices should be doubled and odd indices should double minus one. This is given by A+A-1 for odd entries, and B+B for even entries. So a simple check for whether A or B contains the even points is sufficient, and then simply add the two arrays.
I found this function that does exactly what i wanted:
https://github.com/davidstutz/matlab-multi-label-connected-components
So, clone the repository and compile in matlab using mex :
mex sp_fast_connected_relabel.cpp
Then,
labels = sp_fast_connected_relabel(x);
Within the context of writing a certain function, I have the following example matrix:
temp =
1 2 0 0 1 0
1 0 0 0 0 0
0 1 0 0 0 1
I want to obtain an array whose each element indicates the number of the element out of all non-zero elements which starts that column. If a column is empty, the element should correspond to the next non-empty column. For the matrix temp, the result would be:
result = [1 3 5 5 5 6]
Because the first non-zero element starts the first column, the third starts the second column, the fifth starts the fifth column and the sixth starts the sixth column.
How can I do this operation for any general matrix (one which may or may not contain empty columns) in a vectorized way?
Code:
temp = [1 2 0 0 1 0; 1 0 0 0 0 0; 0 1 0 0 0 1]
t10 = temp~=0
l2 = cumsum(t10(end:-1:1))
temp2 = reshape(l2(end)-l2(end:-1:1)+1, size(temp))
result = temp2(1,:)
Output:
temp =
1 2 0 0 1 0
1 0 0 0 0 0
0 1 0 0 0 1
t10 =
1 1 0 0 1 0
1 0 0 0 0 0
0 1 0 0 0 1
l2 =
1 1 1 1 1 2 2 2 2 2 2 2 3 3 4 4 5 6
temp2 =
1 3 5 5 5 6
2 4 5 5 6 6
3 4 5 5 6 6
result =
1 3 5 5 5 6
Printing values of each step may be clearer than my explanation. Basically we use cumsum to get the IDs of the non-zero elements. As you need to know the ID before reaching the element, a reversed cumsum will do. Then the only thing left is to reverse the ID numbers back.
Here's another way:
temp = [1 2 0 0 1 0; 1 0 0 0 0 0; 0 1 0 0 0 1]; % data
[~, c] = find(temp); % col indices of nonzero elements
result = accumarray(c, 1:numel(c), [], #min, NaN).'; % index, among all nonzero
% values, of the first nonzero value of each col; or NaN if none exists
result = cummin(result, 'reverse'); % fill NaN's using backwards cumulative maximum
This question already has an answer here:
Vector as column index in matrix
(1 answer)
Closed 7 years ago.
While coding in GNU Octave/MATLAB I came through this simple problem I couldn't figure out by myself: I'm trying to select some elements of a matrix by using some indexes stored in an array. Let me put it clear with an example:
Given:
A = zeros(5, 3)
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
I would like to select some elements in A matrix row-wise, by using the values in the auxiliary array B as subindices.
Ie. the following B array
B = [ 1 3 2 1 3 ]'
1
3
2
1
3
should be read as:
1 -> index '1' on first row (element [1, 1])
3 -> index '3' on second row (element [2, 3])
2 -> index '2' on third row (element [3, 2])
1 -> index '1' on fourth row (element [4, 1])
3 -> index '3' on fifth row (element [5, 3])
Therefore, if we assign value '1' to the elements selected using the aforementioned criteria, the resulting matrix would be:
1 0 0
0 0 1
0 1 0
1 0 0
0 0 1
I believe this is a simple operation and I'm convinced that there must be a way to achieve the described behaviour without having to loop across the rows in matrix A.
Thank you.
Edit: Rewrite question so that it is (hopefully) less confusing.
Your question is a bit confusing. You're saying you want to select the elements in A by using the values in the vector B as column indexes, but your example sets (not gets) new values in matrix A. I'm explaining both cases.
Consider this matrix
A = magic(5)
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
Say you want to get/set the diagonal elements of A.
Index pairs in that case are [1,1], [2,2], [3,3], [4,4] and [5,5].
To access elements as a vector, run this
A(sub2ind([5,5], (1:5)',(1:5)'))
17
5
13
21
9
To set elements run this
A(sub2ind([5,5], (1:5)',(1:5)')) = 0
0 24 1 8 15
23 0 7 14 16
4 6 0 20 22
10 12 19 0 3
11 18 25 2 0
These commands can be written as
r = 1:5
c = 1:5
A(sub2ind([max(r),max(c)], r',c'))
# to assign values
A(sub2ind([max(r),max(c)], r',c')) = 0
# and to assign different value to each index pair
A(sub2ind([max(r),max(c)], r',c')) = [20 10 50 12 99]
In your example,
r = 1:5
c = B'
A(sub2ind([max(r),max(c)], r',c')) = 1
# or simply A(sub2ind([max(r),max(B)], r',B)) = 1
1 0 0
0 0 1
0 1 0
1 0 0
0 0 1
You can read how sub2ind works here.
I have a table of rows which consist of zeros and numbers like this:
A B C D E F G H I J K L M N
0 0 0 4 3 1 0 1 0 2 0 0 0 0
0 1 0 1 4 0 0 0 0 0 1 0 0 0
9 5 7 9 10 7 2 3 6 4 4 0 1 0
I want to calculate an average of the numbers including zeros, but starting from the first nonzero value and put it into column after tables end. E.g. for the first row first value is 4, so average - 11/11; for the second - 7/13; the last one is 67/14.
How could I using excel formulas do this? Probably OFFSET with nested IF?
This still needs to be entered as an array formula (ctrl-shift-enter) but it isn't volatile:
=AVERAGE(INDEX(($A2:$O2),MATCH(TRUE,$A2:$O2<>0,0)):$O2)
or, depending on location:
=AVERAGE(INDEX(($A2:$O2);MATCH(TRUE;$A2:$O2<>0;0)):$O2)
The sum is the same no matter how many 0's you include, so all you need to worry about is what to divide it by, which you could determine using nested IFs, or take a cue from this: https://superuser.com/questions/671435/excel-formula-to-get-first-non-zero-value-in-row-and-return-column-header
Thank you, Scott Hunter, for good reference.
I solved the problem using a huge formula, and I think it's a bit awkward.
Here it is:
=AVERAGE(INDIRECT(CELL("address";INDEX(A2:O2;MATCH(TRUE;INDEX(A2:O2<>0;;);0)));TRUE):O2)
actual problem is like this which I got from an Online competition. I solved it but my solution, which is in C, couldn't produce answer in time for large numbers. I need to solve it in C.
Given below is a word from the English dictionary arranged as a matrix:
MATHE
ATHEM
THEMA
HEMAT
EMATI
MATIC
ATICS
Tracing the matrix is starting from the top left position and at each step move either RIGHT or DOWN, to reach the bottom right of the matrix. It is assured that any such tracing generates the same word. How many such tracings can be possible for a given word of length m+n-1 written as a matrix of size m * n?
1 ≤ m,n ≤ 10^6
I have to print the number of ways S the word can be traced as explained in the problem statement. If the number is larger than 10^9+7, I have to print S mod (10^9 + 7).
In the testcases, m and n can be very large.
Imagine traversing the matrix, whatever path you choose you need to take exatcly n+m-2 steps to make the word, among of which n-1 are down and m-1 are to the right, their order may change but the numbers n-1 and m-1 remain same. So the problem got reduced to only select n-1 positions out of n+m-2, so the answer is
C(n+m-2,n-1)=C(n+m-2,m-1)
How to calculate C(n,r) for this problem:
You must be knowing how to multiply two numbers in modular arithmetics, i.e.
(a*b)%mod=(a%mod*b%mod)%mod,
now to calculate C(n,r) you also need to divide, but division in modular arithmetic can be performed by using modular multiplicative inverse of the number i.e.
((a)*(a^-1))%mod=1
Ofcourse a^-1 in modular arithmetic need not equal to 1/a, and can be computed using Extended Euclidean Algorithm, as in your case mod is a prime number therefore
(a^(-1))=a^(mod-2)%mod
a^(mod-2) can be computed efficiently using repetitive squaring method.
I would suggest a dynamic programming approach for this problem since calculation of factorials of large numbers shall involve a lot of time, especially since you have multiple queries.
Starting from a small matrix (say 2x1), keep finding solutions for bigger matrices. Note that this solution works since in finding the solution for bigger matrix, you can use the value calculated for smaller matrices and speed up your calculation.
The complexity of the above soltion IMO is polynomial in M and N for an MxN matrix.
Use Laplace's triangle, incorrectly named also "binomial"
1 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
1 1 0 0 0
1 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
1 1 1 0 0
1 2 0 0 0
1 0 0 0 0
0 0 0 0 0
0 0 0 0 0
1 1 1 1 0
1 2 3 0 0
1 3 0 0 0
1 0 0 0 0
0 0 0 0 0
1 1 1 1 1
1 2 3 4 0
1 3 6 0 0
1 4 0 0 0
1 0 0 0 0
1 1 1 1 1
1 2 3 4 5
1 3 6 10 0
1 4 10 0 0
1 5 0 0 0
1 1 1 1 1
1 2 3 4 5
1 3 6 10 15
1 4 10 20 0
1 5 15 0 0
1 1 1 1 1
1 2 3 4 5
1 3 6 10 15
1 4 10 20 35
1 5 15 35 0
1 1 1 1 1
1 2 3 4 5
1 3 6 10 15
1 4 10 20 35
1 5 15 35 70
Got it? Notice, that elements could be counted as binomial members. The diag members are here: C^1_2, C^2_4,C^3_6,C^4_8, and so on. Choose which you need.