Я не совсем понимаю, что ты хочешь делать. Тем не менее, кажется, что обрабатывать массив много раз - пустая трата времени. Вы все могли бы сделать только один цикл (и немного заглядывать вперед, когда у вас заканчиваются «свободные» уникальные значения). Следующее, конечно, не самый хороший код, который я написал, но я думаю, что это решение вашей проблемы.
HashSet<long> forbidden = new HashSet<long>(); // maximum size of 1000, contains values that exceeded the limit
Queue<long> remaining = new Queue<long>(1000); // stores found unique values within the limit in a queue, that will be used if we bounce into the limit
Dictionary<long, int> frequencies = new Dictionary<long, int>(1000);
int lastPeekIndex = 0;
for (int i = 0; i < Arr.Length; i++) {
if (!frequencies.ContainsKey(Arr[i])) {
frequencies[Arr[i]] = 0;
remaining.Add(Arr[i]);
}
if (frequencies[Arr[i]] == upperLimit) {
if (!forbidden.Contains(Arr[i])) forbidden.Add(Arr[i]);
var next = Int64.MinValue;
try {
next = remaining.Dequeue();
while (forbidden.Contains(next)) next = remaining.Dequeue();
} catch (InvalidOperationException) { // Arrr! we have not yet observed enough unique values
for (int j = Math.Max(i, lastPeekIndex) + 1; j < Arr.Length; j++)
if (!frequencies.ContainsKey(Arr[j])) {
frequencies[Arr[j]] = 0;
next = Arr[j];
lastPeekIndex = j;
}
}
Arr[i] = next;
frequencies[next]++;
if (frequencies[next] < upperLimit) remaining.Enqueue(next);
} else frequencies[Arr[i]]++;
}
Обратите внимание, что это не проверяет нижний предел, так как вы также не проверяли это. Я думаю, что вы должны заботиться о значениях, которые встречаются недостаточно часто во втором проходе. Вы можете поместить их в другую очередь после первого прохода, а затем выполнять итерации по массиву снова и снова, пока очередь не станет пустой (вероятно, даже меньше, чем одна полная итерация необходима во втором проходе).