【问题标题】:Sorting a list in ascending and descending order按升序和降序对列表进行排序
【发布时间】:2016-10-18 03:23:31
【问题描述】:

我有一个整数集合,例如

输入示例

4,7,9,8,20,56,78,34,2,76,84,98

我需要以一种方式对这个列表进行排序,直到 20 的任何数字都将按升序排序,而 20 以上的数字将按降序排序。所以输出将是:

输出示例

2,4,7,8,9,20,98,84,78,76,56,34

我为它写了一个比较器。但现在尝试更干净的方法可能是使用现有的工具,如 orderby。

【问题讨论】:

  • 你能分享你的代码吗?有用吗?

标签: c# linq


【解决方案1】:

您可以使用两个排序组来做到这一点:

list.OrderBy(i => i <= 20 ? i : int.MaxValue) // sort numbers less than 20 ascending; put numbers greater than 20 at the end
    .ThenByDescending(i => i)  // sort remaining numbers descending

【讨论】:

  • ? 0 : 1 是不必要的;您可以按布尔值排序。
  • @Servy: 但是你必须使用OrderByDescending 或反转条件。实际上0 : 1 更具可读性。
  • @Servy 是的,但我不喜欢记住 truefalse 是否在前,所以我只使用 0 和 1,以免弄错。跨度>
  • 很好的解决方案,但我认为可以通过使用两个排序组而不是像这样的三个排序组来完成:list.OrderBy(i =&gt; i &lt;= 20 ? i : int.MaxValue).ThenByDescending(i =&gt; i);。对吗?
  • @S.Akbari 是的,你可以 - 第一个排序会有效地将较高的数字移到最后。接得好。我已经编辑了答案以表明这一点。
【解决方案2】:

您可以使用自定义比较器轻松做到这一点:

public class MyCustomComparer : IComparer<int>
{
    private readonly int _cutOffPointInclusive;

    public MyCustomComparer(int cutOffPointInclusive)
    {
        _cutOffPointInclusive = cutOffPointInclusive;
    }

    public int Compare(int x, int y)
    {
        if (x <= _cutOffPointInclusive || y <= _cutOffPointInclusive)
        {
            return x.CompareTo(y);
        }
        else 
        {               
            return y.CompareTo(x);
        }
    }
}

当要比较的任何一个值小于或等于截止点时,这会升序排序(将较大的值推到顶部并按升序对值进行排序直到截止点),并且当两者都大于时降序排列截止点(实际上是按降序对较大的值进行排序)。

测试使用:

var testData = new List<int>{ 4,7,9,8,20,56,78,34,2,76,84,98 };

testData.Sort(new MyCustomComparer(20));

foreach (var i in testData)
{
    Console.WriteLine(i);
}

输出:

2
4
7
8
9
20
98
84
78
76
56
34

另见http://ideone.com/YlVH8i。所以我真的不认为这不“干净”,但很好。

【讨论】:

  • 这是我的第一选择...但是您不认为在可维护性部分...因为任何应用程序都会增长...这些自定义算法会以某种方式丢失。只是想知道另一个想法:)
  • @AshishRajput FWIW 当我有特定类型的自定义比较器时,我通常会在该类型中创建私有(或必要时公共)类。这样它们就与类型相关联并且不会“迷失”。当然,您的自定义比较器是针对数组的,所以这里不是一个选项,但可能需要考虑。
【解决方案3】:

为什么不使用两个步骤?

var bellow = originallist.Where(i => i <= 20).OrderBy(i);
var above= originallist.Where(i => i > 20).OrderByDescending(i);

var sorted = bellow.Concat(above).ToList();

【讨论】:

  • 因为这是你能得到的最糟糕的表现?
  • 是的,微优化是这个问题中最重要的。
  • 性能怎么样。这只是我的问题的一个快照,但我的实际数据非常大
  • @MarkoJuvančič 昂贵操作的算法不是微优化。算法级别的决策是宏观优化。
  • @Henrik Where().Where().Concat(),一个。
【解决方案4】:
int[] a = { 4, 7, 9, 8, 20, 56, 78, 34, 2, 76, 84, 98 };

var b = a.OrderBy(i => i > 20 ? int.MaxValue - i : i);

如果可能,我建议就地排序。例如(可以改进)

Array.Sort(a, (i1, i2) => (i1 > 20 ? int.MaxValue - i1 : i1) - (i2 > 20 ? int.MaxValue - i2 : i2));

【讨论】:

    【解决方案5】:
    [Test]
            public void SortTill20AscRestDesc()
            {
                var src = new[] {4, 7, 9, 8, 20, 56, 78, 34, 2, 76, 84, 98};
                var expected = new[] {2, 4, 7, 8, 9, 20, 98, 84, 78, 76, 56, 34};
                var result = src
                    .Select(
                        i => new
                        {
                            IsAbove20 = i > 20,
                            Value = i
                        }
                    )
                    .OrderBy(e => e.IsAbove20)
                    .ThenBy(e => e.IsAbove20 ? int.MaxValue : e.Value)
                    .ThenByDescending(e => e.Value)
                    .Select(e=>e.Value);
    
                Assert.That(result.SequenceEqual(expected), Is.True);
            }
    

    【讨论】:

    • 这与一小时前发布的答案没有太大的不同。
    猜你喜欢
    • 2020-10-05
    • 1970-01-01
    • 1970-01-01
    • 2020-11-09
    • 2018-05-03
    • 1970-01-01
    • 2015-08-30
    • 2011-07-17
    相关资源
    最近更新 更多