我建议分组重复,然后循环考虑组的大小:
public static IEnumerable<List<T>> MyDo<T>(IEnumerable<T> source,
IEqualityComparer<T> comparer = null) {
if (null == source)
throw new ArgumentNullException(nameof(source));
var groups = new Dictionary<T, List<T>>(comparer ?? EqualityComparer<T>.Default);
int maxLength = 0;
foreach (T item in source) {
if (!groups.TryGetValue(item, out var list))
groups.Add(item, list = new List<T>());
list.Add(item);
maxLength = Math.Max(maxLength, list.Count);
}
for (int i = 0; i < maxLength; ++i) {
List<T> result = new List<T>();
foreach (var value in groups.Values)
if (i < value.Count)
result.Add(value[i]);
yield return result;
}
}
演示:
int[] source = new int[] { 1, 1, 2, 5, 7, 2, 2, 2, 6, 1 };
var result = MyDo(source).ToList();
string report = string.Join(Environment.NewLine, result
.Select(line => $"[{string.Join(", ", line)}]"));
Console.Write(report);
结果:
[1, 2, 5, 7, 6]
[1, 2]
[1, 2]
[2]
压力演示:
Random random = new Random(1234); // seed, the results to be reproducible
// We don't want 1000 items be forever; let's try 1_000_000 items
int[] source = Enumerable
.Range(1, 1_000_000)
.Select(x => random.Next(1, 1000))
.ToArray();
Stopwatch sw = new Stopwatch();
sw.Start();
var result = MyDo(source).ToList();
sw.Stop();
Console.WriteLine($"Time: {sw.ElapsedMilliseconds} ms");
结果:(可能因工作站而异)
Time: 50 ms