필터 지우기
필터 지우기

creating a matrix where the element of the second column is smaller than the element of the first column

조회 수: 1 (최근 30일)
I would like to create a matrix where the element of the second column is smaller than the element of the first column. For example,
A = [1 1; 2 1; 2 2; 3 1; 3 2; 3 3]
I would like to know a simpler way rather than going through loops.

채택된 답변

Guillaume
Guillaume 2017년 12월 20일
In terms of clarity and speed, a loop is probably the best, I'd implement it as:
n = 4; %largest number
result = zeros(n*(n+1)/2, 2);
row = 1;
for i = 1:n
result(row:row+i-1, :) = [repmat(i, i, 1), (1:i)'];
row = row+i;
end
You can implement the above with arrayfun as James has done, but it's likely to be slower.
Another fancy non-loopy way of getting the result:
n = 4;
result = [repelem((1:n)', 1:n), flipud(nonzeros(hankel(n:-1:1)))]
The use of hankel to obtain the 2nd column is fairly obscure so I wouldn't recommend using that.
  댓글 수: 2
Guillaume
Guillaume 2017년 12월 20일
편집: Guillaume 2017년 12월 20일
For comparison, a quick performance test on my machine (R2017a) of the 3 solutions proposed:
For some reason they all slow down suddenly at around n=350. For smaller n, the hankel version is actually faster, but for larger n the performance degrades quadratically (probably). The arrayfun version is always significantly slower than the loop version.
Guillaume
Guillaume 2017년 12월 21일
편집: Guillaume 2017년 12월 21일
New comparison that includes all the valid proposed solutions, on a different machine and different version (R2017b):
For low n Roger's answer is the fastest. nchoose2 (without the sort) and my hankel version are on par. Jame's arrayfun solution is consistently slower than the explicit loop and nchoose2 with sorting is a disaster. The explicit loop is never much slower than the fastest solution and for n>500 (on that machine) is the best solution.
I'd say go with a loop as it's by far the clearest as to what it does.

댓글을 달려면 로그인하십시오.

추가 답변 (5개)

James Tursa
James Tursa 2017년 12월 20일
편집: James Tursa 2017년 12월 20일
E.g.,
n = largest number (e.g., 3)
result = cell2mat(arrayfun(@(x)[ones(x,1)*x,(1:x)'],1:n,'uni',false)');
  댓글 수: 2
James Tursa
James Tursa 2017년 12월 20일
Start with the function:
@(x)[ones(x,1)*x,(1:x)']
For an integer input x, this creates a 2-column matrix. The first column is all the number x, and the second column is the numbers 1 through x. E.g.,
>> f = @(x)[ones(x,1)*x,(1:x)']
f =
@(x)[ones(x,1)*x,(1:x)']
>> f(1)
ans =
1 1
>> f(2)
ans =
2 1
2 2
>> f(3)
ans =
3 1
3 2
3 3
>> f(4)
ans =
4 1
4 2
4 3
4 4
The @(x) anonymous function is fed into the arrayfun( ) function as the first argument.
The second argument to arrayfun( ) is the array 1:n. So, for each number in the second argument, arrayfun( ) will execute the @(x) function with this number as the input. The output of each "iteration" of arrayfun( ) is a matrix and not a scalar. So to gather up all of these outputs into a single cell array result, we also give the last two arguments 'uni' and false.
The cell2mat call simply concatenates all of the cell array results that came from the arrayfun( ) call into a single matrix. The transpose operator ' is used to ensure the concatenation happens vertically (1:n is a row vector so the cells come out as a row vector as well, but we want them stacked vertically).

댓글을 달려면 로그인하십시오.


Image Analyst
Image Analyst 2017년 12월 20일
Here are a couple of ways, one by sorting and one by replacing the second column:
A = [1 1; 2 1; 2 2; 3 1; 3 2; 3 3]
% Sort descending.
ASorted = sort(A, 2, 'descend')
% Replace second row
A2 = A;
A2(:, 2) = A(:, 1) - 1; % Column 2 is one less than col 1

Roger Stafford
Roger Stafford 2017년 12월 21일
Here's another way:
N = 10; % Choose any integer N (largest number)
n = (1:N*(N+1)/2)';
c1 = round(sqrt(2*n-3/4));
c2 = n-(c1-1).*c1/2;
A = [c1,c2];
  댓글 수: 3
Image Analyst
Image Analyst 2017년 12월 21일
Oh, I see now. You and Guillaume were generalizing the matrix alpedhuez gave to larger versions, assuming some algorithm, while I didn't do that and just took the "A" as the given matrix, A = [1 1; 2 1; 2 2; 3 1; 3 2; 3 3], which he needed to create/modify a matrix from that given matrix where the second column was less than the first. I can see there is a possibly ambiguity in interpretation when he gives A and says he needs to create a matrix, that hopefully the poster can clear up.

댓글을 달려면 로그인하십시오.


Jos (10584)
Jos (10584) 2017년 12월 21일
Another approach:
n = 7 ;
M = [n+1-nchoose2(1:n) ; repmat(1:n,2,1).'] % voila!
M_sorted = sortrows(M) % in sorted order, but why bother
NCHOOSE2 is my very fast simple utility function to get combinations of 2 elements from a vector (like nchoosek(V,2), but way more efficient). It can be downloaded from the File Exchange:

Jos (10584)
Jos (10584) 2017년 12월 21일
And here is a one-liner (using only MatLab functions).
n = 5 ;
M = flipud(nchoosek(n:-1:0,2) + [0 1]) % + expansion works in later ML releases
Replace NCHOOSEK by NCHOOSE2 (see my other answer) for an efficient improvement :D

카테고리

Help CenterFile Exchange에서 Loops and Conditional Statements에 대해 자세히 알아보기

태그

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by