Я думаю, что достаточно проверить следующее условие, чтобы предотвратить бесконечные циклы:
[~,num, C] = mode(myArr);
N = numel(C);
assert( (myDist<=N) || (myDist-N+1) * (num-1) +N*num <= numel(myArr),...
'Shuffling impossible!');
Предположим, что myDist
равно 2
, и у нас есть следующие данные:
[4 6 5 1 6 7 4 6]
Мы можем найти режим, 6
, с его появлением, 3
.Мы организуем 6
s, разделяя их на 2 = myDist
пробелы:
6 _ _ 6 _ _6
Для заполнения пробелов должно быть (3-1) * myDist = 4
чисел.Теперь у нас есть еще пять чисел, поэтому массив можно перемешать.
Проблема становится более сложной, если у нас несколько режимов.Например, для этого массива [4 6 5 1 6 7 4 6 4]
у нас есть режимы N=2
: 6
и 4
.Они могут быть расположены следующим образом:
6 4 _ 6 4 _ 6 4
У нас есть 2 пробела и еще три числа [ 5 1 7]
, которые можно использовать для заполнения пробелов.Например, если бы у нас было только одно число [ 5]
, было бы невозможно заполнить пробелы и мы не могли бы перемешать массив.
Для третьего пункта вы можете использовать разреженную матрицу для ускорения вычислений (мое первоначальное тестирование в Octave показывает, что оно более эффективно):
function shuffledArr = distShuffleSparse(myArr, myDist)
[U,~,idx] = unique(myArr);
reps = true;
while reps
S = Shuffle(idx);
shuffledBin = sparse ( 1:numel(idx), S, true, numel(idx) + myDist, numel(U) );
reps = any (diff(find(shuffledBin)) <= myDist);
end
shuffledArr = U(S);
end
В качестве альтернативы вы можете использовать sub2ind и сортировка вместо разреженной матрицы:
function shuffledArr = distShuffleSparse(myArr, myDist)
[U,~,idx] = unique(myArr);
reps = true;
while reps
S = Shuffle(idx);
f = sub2ind ( [numel(idx) + myDist, numel(U)] , 1:numel(idx), S );
reps = any (diff(sort(f)) <= myDist);
end
shuffledArr = U(S);
end