Sorting numbers randomly in a specified range without changing their positions

A = [5 8 8 4 0 0 10 10 2 2];
Since A is in the range of 1:10, I want to sort A such that all the repeated numbers are replaced with numbers that hasn't appeared yet within 1 to 10, slotting those numbers in, randomly, without ascending or descending. All their initial positions should be maintained without changing. All zeros will also be replaced with non-zeros in this specified range. Maybe to get a result like below.
Ans = [5 8 1 4 7 3 10 6 9 2];

 Accepted Answer

% Input
A = [5 8 8 4 0 0 10 10 2 2];
% Find the pool of numbers that are available to fill
% (because they don't appear in A, but are in 1:10, in this case)
pool = setdiff(1:numel(A),unique(A));
% Find the locations to place the numbers
% (i.e. repeats and zeros)
loc = (diff([NaN A]) == 0) | (A==0);
% Fill the locations randomly from the pool
A(loc) = pool(randperm(numel(pool)))
A = 1×10
5 8 7 4 1 6 10 9 2 3

12 Comments

Thank you. It worked. But it didn't work for what I intend using it for. There are two issues... First is that A doesn't consist zeros, I made mistake putting zeros. So, assuming those zeros are ones, I went ahead to edit/erase the second part of line 8 of the code as below, and it worked.
loc = (diff([NaN A]) == 0);
The second issue is that I intend running this process for 50 particle solutions. I edited it into for-loop as below but I'm still getting repeated numbers in each solutions of the particles. Please help.
for i = 1:50
pool = setdiff(1:numel(p(i).Pos),unique(p(i).Pos));
loc = (diff([NaN p(i).Pos] ) == 0);
p(i).Pos(loc) = pool(randperm(numel(pool(i) )))
end
p(i).Pos is the 50 particles consisting of their solutions I intend working on.
Can you upload an example of an input that does not give the expected result, and what you expected to see?
You could upload the data directly, ideally in a mat file, using the paperclip icon in the INSERT section of the toolbar.
I have uploaded it to Dropbox link below because it contains different scripts to call. The main file is the PSO.m at line 100.
https://www.dropbox.com/s/way37zllcq0uzfg/UploadMathwork.rar?dl=0
Sorry, I don't really want to download, unzip, figure out how to run your scripts, etc.
Can you please just upload and example of one vector that my algorithm does not give the expected result for?
for i = 1:50
% A vector scenario 'p' has been attached for illustration
pool = setdiff(1:numel(p(i).Pos),unique(p(i).Pos));
loc = (diff([NaN p(i).Pos]) == 0);
p(i).Pos(loc) = pool(randperm(numel(pool(i))));
% what is exxpected is not to see any repeated numbers in the
% updated solutions of p(i).Pos
end
Unrecognized function or variable 'p'.
Ah, I see. The problem is that in your original question, the repeated numbers were always consecutive, so my solution assumed that to be the case. Here is a modified solution:
% Input
A = [5 8 8 4 1 1 10 10 2 2 8];
% Find the unique values in A, and the locations of the first instance of
% those values
[uniqueA,locationFirstInstance] = unique(A);
% Find the pool of numbers that are available to fill
% (because they don't appear in A, but are in 1:11, in this case)
entireSet = 1:numel(A);
pool = setdiff(entireSet,unique(A));
% Find the locations of the repeated instances
loc = setdiff(entireSet,locationFirstInstance);
% Fill the locations randomly from the pool
A(loc) = pool(randperm(numel(pool)))
A = 1×11
5 8 11 4 1 3 10 7 2 6 9
You should be able to swap in p(i).Pos for A again, in your actual code.
Again it worked for A but didn't work for the particle loop p(i).Pos. The updated p(i).Pos still consists of repeated numbers. For example, the first particle p(1).Pos has the number 13 repeated three times in column 6, column 7 and column 8. Below is how I edited your code.
for i = 1:50
[uniqueP,locationFirstInstance] = unique(p(i).Pos);
entireSet = 1:numel(p(i).Pos);
pool = setdiff(entireSet,unique(p(i).Pos));
loc = setdiff(entireSet,locationFirstInstance);
p(i).Pos(loc) = pool(randperm(numel(pool(i))));
end
You had a small typo, which is corrected below:
for i = 1:50
[uniqueP,locationFirstInstance] = unique(p(i).Pos);
entireSet = 1:numel(p(i).Pos);
pool = setdiff(entireSet,uniqueP); % <---- I also made a small edit to this line, but it doesn't affect the algorithm
loc = setdiff(entireSet,locationFirstInstance);
p(i).Pos(loc) = pool(randperm(numel(pool))); % <--- Typo: You had numel(pool(i))
end
Please I still have one more concern. What if the variable is in the form "sol(i,:)" instead of "p(i).Pos"?
Where my problem at is in the last line of the code.
for i = 1:50
[uniqueP,locationFirstInstance] = unique(Sol(i,:));
entireSet = 1:numel(Sol(i,:));
pool = setdiff(entireSet,uniqueP);
loc = setdiff(entireSet,locationFirstInstance);
(Sol(i,:)(loc)) = pool(randperm(numel(pool))); % <--- LHS: I'm having problem in assigning the variable name for loc
end

Sign in to comment.

More Answers (0)

Categories

Products

Release

R2020a

Community Treasure Hunt

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

Start Hunting!