随机排列一组不均匀重复的条目,因此它们不会重复

Shuffle an array of unequally repeating entries, so they do not repeat

我正在 Matlab Psychtoolbox 中编写一个实验,我的条件存储在这样的数组中

Cond = ["VM" "VM" "VN" "VS" "AM" "AM" "AN" "AS" "CM" "CM" "CN" "CS"...
"VM" "VM" "VN" "VS" "AM" "AM" "AN" "AS" "CM" "CM" "CN" "CS"];

我现在想以一种没有重复条件的方式打乱数组。

有很多关于这个问题的治疗,例如this one,但他们总是同样经常遇到每个条件。

有些人提出了一种蛮力方法,经常洗牌直到达到这个标准。但是因为我有这个条件数组的树,我必须在每个实验中将它们洗牌几次 运行 我认为这不是一个好的解决方案。

希望有人能帮忙

我设计了一个算法来满足您的要求。给定一个序列,它将随机重新排序,使得没有值重复。然而,它似乎确实倾向于创建重复的子序列(例如 ..."A" "B" "C" "A" "B" "C"...)。我把它包装在一个函数中 reorder_no_reps:

function seq = reorder_no_reps(seq)

  % Find unique values and counts:
  N = numel(seq);
  [vals, ~, index] = unique(seq(:), 'stable');
  counts = accumarray(index, 1);
  [maxCount, maxIndex] = max(counts);

  % Check the maximum number of occurrences:
  if (2*maxCount-1 > N)
    error('Can''t produce sequence without repeats!');
  end

  % Fill cell array column-wise with permuted and replicated set of values:
  C = cell(maxCount, ceil(N/maxCount));
  if (3*maxCount-1 > N)
    permIndex = [maxIndex(1) ...
                 setdiff(randperm(numel(vals)), maxIndex(1), 'stable')];
  else
    permIndex = randperm(numel(vals));
  end
  C(1:N) = num2cell(repelem(vals(permIndex), counts(permIndex)));

  % Transpose cell array and extract non-empty entries:
  C = C.';
  seq = reshape([C{~cellfun('isempty', C)}], size(seq));

end

算法步骤说明:

  • 找出输入序列中的唯一值 (vals) 以及它们各自出现的次数 (counts)。
  • 找到单个值的最大出现次数 (maxCounts) 并检查它是否太大而无法在没有重复的情况下生成序列。
  • 随机排列顺序应用于唯一值及其计数。如果最大出现次数超过给定阈值,则相应的值索引将移动到随机顺序的开头(原因在下一个项目符号中解决)。
  • 然后根据序列中出现的次数将每个唯一值复制到位。使用这些复制的值按列顺序填充元胞数组,最后可能会留下一些元胞为空。由于元胞数组的行数等于某个值的最大出现次数,因此生成的元胞数组的任何一行都不会有一个值在其中出现多次。此外,每行中的最后一个值应不同于后续行中的第一个值(在某些情况下首先填充最常出现的值以确保)。
  • 转置元胞数组,然后按列顺序拉取所有非空元胞值,并将它们重新整形为与输入序列相同的大小。这与从非转置元胞数组中逐行提取值相同,这应该为您提供一个没有重复值的序列。