C#按序列分区排序编号

时间:2018-06-12 08:27:33

标签: c#

我的数据如下:

5 2 2 1 3 3 4

我希望C#中的输出如下:

1 2 3 4 五 2 3

所以基本上所有唯一值首先按照ASC顺序排序,然后再从剩余项目开始......

2 个答案:

答案 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);