choose one out of every 8 elements randomly

I have a 1xm matrix and I want to choose one out of every 8 elements randomly, I can think of ways using for loops but I was hoping for a solution without for loops and efficient in terms of speed. Thanks

 采纳的回答

m = 21;
A = (1:m)+0.314;
nof8 = ceil(m/8);
randSelect = randi([1 8],1,nof8);
inds = randSelect+(0:nof8-1)*8;
% if m is not a multiple of 8 the last samples must get special treatment
% the simplest solution is to limit the indices in inds to the m
inds(end)=min(inds(end),m);
% but this leads to a non-uniform distribution for the last selection.
selectedElements = A(inds)
A solution with an uniform distribution for all cases was suggested from Guillaume:
randselect = randi(8, 1, floor(numel(A)/8));
if mod(numel(A), 8) > 0
randselect = [randselect, randi(mod(numel(A), 8))];
end
selectedvalues = A(randselect + (0:ceil(numel(A)/8)-1)*8)

11 个评论

Cheers exactly what I needed! Kindly can you please explain what this line is doing since I'm not understanding its function..I'm still getting the required results without it. Thanks again
inds(end)=min(inds(end),m);
In the vector inds there are the indices of the selected elements. If m is not a multiple of 8, it is possible that the last index is greater than m (the length of your input signal). In this case the last index in inds is set to m (that is the last element of your input signal).
It is the simplest way to deal with vectors with a length different to x*8.
I couldn't resist the urge to create this one-liner:
selectedElements = A(arrayfun(@(k) randi([k min(k+8-1,number(A))],1),1:8:number(A)))
The solution may not have the problem of reshaping (is it a problem?), but it has the problem that the selection of the last block is strongly non-uniform. If there are only two elements in the last block, you have a 7/8 chance of selecting the 2nd.
a better solution would be:
randselect = randi(8, 1, floor(numel(A)/8));
if mod(numel(A), 8) > 0
randselect = [randselect, randi(mod(numel(A), 8))];
end
selectedvalues = A(randselect + (0:ceil(numel(A)/8)-1)*8)
@Jos: I like it! A one-liner is always very pretty, but difficult to read and understand.
@Guillaume: That's right, but as i have noted it is the simplest way. It may be non-uniform but it is random. The perfect solution for the problem with the incomplete last 'subarray' depends on the purpose of the algorithm. In addition I don't want to solve all possible problems that my occur, my goal is it to give a quick idea of one possible solution for the problem. So that the reader can implement the specific solution for his problem.
@Guillaume: Reshaping is only a 'problem' if m is not a multiple of 8. The term problem in my first answer is a little bit strong. I wanted to state that this solution don't need an assert for this case.
@Goerk: Yes, reshaping is a problem if m is not a multiple of 8, but as you pointed out, we don't have enough information from the OP to know if it is. However, if it is, I would think that a bias for the last value of the last block would also be a problem.
I think it is important to warn the OP of that bias as they may not have realised it. Worse than a solution than does not solve the problem is a solution that appears to solve the problem but fails on some edge cases.
Yes that's true and therefor thanks for the hint. I will add a comment to the initial code snippet to clarify that.
Hi All sorry for my late reply but for the required problem m will always be divisible by 8 (therefore I will not have any bias problems):) I really appreciate all your help..all solutions were good I just chose the one which seemed most easy given my programming experience
@goerk is it possible to generalise the first section of code you gave me from which i can then choose either 1 every 8, 2 every 8 elements or 3 every 8 elements?
Select multiple (unique) Samples:
m = 21;
A = (1:m)+0.314;
nof8 = floor(m/8); %floor-> if m ~= x*8 ignore last samples
nofSamples = 2;
randSelect = zeros(nofSamples,nof8);
for i=1:nof8
randSelect(:,i)= randperm(8,nofSamples);
end
inds = randSelect+repmat((0:nof8-1)*8,nofSamples,1);
selectedElements = A(inds)
Since the number of elements is always multiple of 8, this is a case where using reshape is a lot more elegant.
A = 1:104;
nofsamples = 3;
A8 = reshape(A, 8, []);
selectedelements = A8(sub2ind(size(A8), randperm(8, nofsamples), 1:size(m8, 2)))
%if required as a vector:
selectedelements = selectedelements(:)

请先登录,再进行评论。

更多回答(2 个)

One possible way:
m = 1:104; %input
assert(mod(numel(m), 8) == 0, 'the number of elements in m must be a multiple of 8');
m8 = reshape(m, 8, []);
m8(sub2ind(size(m8), randi(8, 1, size(m8, 2)), 1:size(m8, 2)))
m = 100;
spacedIds = [0:8:m];
rands = randi(8, 1, size(spacedIds,2)-1);
randIds = spacedIds(1:end-1)+ rands;
% check if m is not a multiple of 8
% add another number from the remaining tail-section
if ~(spacedIds(end) == m)
randIds(end+1) = spacedIds(end) + randi(m-spacedIds(end), 1,1);
end

类别

帮助中心File 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