Shuffle a vector of repeated numbers so the number

2019-08-10 15:05发布

问题:

Okay, so I have a script that will produce my vector of repeated integers of a certain interval, but now theres a particular instance where I need to make sure that once it is shuffled, the numbers do not repeat. So for example, I produced a vector of repeating 1-5, 36 times, shuffled. How do I ensure that there are no repeated numbers after shuffling? And to make things even more complex, I need to produce two such vectors that do not ever have the same value at the same index. For example, lets say 1:5 was repeated twice for these vectors, so then this would be what I'm looking for:

v1     v2
4      2
2      4
3      2
5      3
4      5
1      4
5      1
1      5
3      1
2      3

I made that right now by taking an example of 1 vector and just shifting it off by 1 to create another vector that will satisfy the requirements, but in my situation, that wont actually work because I can't have them be systematically dependent like that.

So I tried a recursive technique to make the script start over if the vectors did not make the cut and as expected, that did not go over so well. I hit my maximum recursive iterations and I've realized this is clearly not the way to go. Is there some other alternative?

EDIT:

So I found a way to satisfy some of the conditions I needed above in the following code:

a = nchoosek(1:5,2);
b = horzcat(a(:,2),a(:,1));
c = vertcat(a,b);

cols = repmat(c,9,1);
cols = cols(randperm(180),:);

I just need to find a way to shuffle cols that will also enforce no repeating numbers in columns, such that cols(i,1) ~= cols(i+1,1) and cols(i,2) ~= cols(i+1,2)

回答1:

This works, but it probably is not very efficient for a large array:

a = nchoosek(1:5, 2);
while (any(a(1: end - 1, 1) == a(2: end, 1)) ...
    || any(a(1: end - 1, 2) == a(2: end, 2)))
    random_indices = randperm(size(a, 1));
    a = a(random_indices, :);
end
a

If you want something faster, the trick is to logically insert each row in a place where your conditions are satisfied, rather than randomly re-shuffling. For example:

n1 = 5;
n2 = 9;

a = nchoosek(1:n1, 2);
b = horzcat(a(:,2), a(:,1));
c = vertcat(a, b);
d = repmat(c, n2, 1);
d = d(randperm(n1 * n2), :);

% Perform an "insertion shuffle"
for k = 2: n1 * n2

    % Grab row k from array d.  Walk down the rows until a position is
    % found where row k does not repeat with its upstairs or downstairs
    % neighbors.
    m = 1;
    while (any(d(k,:) == d(m,:)) || any(d(k,:) == d(m+1,:)))
        m = m + 1;
    end

    % Insert row k in the proper position.
    if (m < k)
        ind = [ 1: m  k  m+1: k-1   k+1: n1 * n2 ];
    else
        ind = [ 1: k-1   k+1: m  k  m+1: n1 * n2 ];
    end

    d = d(ind,:);
end
d


回答2:

One way to solve this problem is to think both vectors as being created as follows:

For every row of arrays v1 and v2

  • Shuffle the array [1 2 3 4 5]
  • Set the values of v1 and v2 at the current row with the first and second value of the shuffle. Both values will always be different.

Code:

s = [1 2 3 4 5];
Nrows = 36;
solution = zeros(Nrows,2);
for k=1:Nrows
   % obtain indexes j for shuffling array s
   [x,j] = sort(rand(1,5));
   %row k takes the first two values of shuffled array s
   solution(k,1:2) = s(j(1:2));
end
v1 = solution(:,1);
v2 = solution(:,2);

Main edit: random => rand,

With this method there is no time wasted in re-rolling repeated numbers because the first and second value of shuffling [1 2 3 4 5] will always be different. Should you need more than two arrays with different numbers the changes are simple.