我的数据如下:
5 2 2 1 3 3 4
我希望C#中的输出如下:
1 2 3 4 五 2 3
所以基本上所有唯一值首先按照ASC顺序排序,然后再从剩余项目开始......
答案 0 :(得分:2)
我会说这很复杂......但它引起了我的兴趣......注意这个解决方案非常简单。如果您想要多字段排序或反向排序等等,它会变得更加复杂:
public static class OrderByTest
{
private static int Increment<TKey>(Dictionary<TKey, int> dict, TKey key)
{
int value;
if (dict.TryGetValue(key, out value))
{
value++;
}
dict[key] = value;
return value;
}
public static IEnumerable<TSource> OrderByPartition<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
var dict = new Dictionary<TKey, int>();
var res = source.Select(x => new { Value = x, Partition = Increment(dict, keySelector(x)) }).OrderBy(x => x.Partition).ThenBy(x => keySelector(x.Value));
foreach (var value in res)
{
yield return value.Value;
}
}
}
然后使用它:
var values = new[] { 5, 2, 2, 1, 3, 3, 4 };
var ordered = values.OrderByPartition(x => x).ToArray();
它是Linq风格的解决方案,因此它生成一个新的有序序列,而不是Array.Sort
之类的就地解决方案。基本思路是将分区号添加到您的集合中。要获得分区号,我们使用一个临时Dictionary<TKey, int>
,其中包含已找到的具有相同TKey
的元素数。
答案 1 :(得分:1)
您可以按值对数据进行分组,对组进行排序,然后迭代记住计数的组 - 每次递减并在达到零时删除内容,或者递增计数器并仅输出至少为人口众多。类似的东西:
var values = new[] { 5, 2, 2, 1, 3, 3, 4 };
var data = new SortedDictionary<int, int>();
foreach(var val in values)
{
int count;
if (!data.TryGetValue(val, out count)) count = 0;
data[val] = count + 1;
}
int lim = 0;
bool any;
do
{
any = false;
foreach (var pair in data)
if (pair.Value > lim)
{
Console.WriteLine(pair.Key);
any = true;
}
lim++;
} while (any);