如何按多个条件对Swift对象进行排序

时间:2014-11-03 23:33:08

标签: sorting swift

我有一个Swift对象列表,我希望按多个条件对其进行排序。列表中的对象类型为DateRange

class DateRange {
    var from: NSDate?
    var to: NSDate?
}

该列表包含许多这些对象,其中一些fromto字段为零。我希望将此列表排序依据:

  1. 首先是所有具有日期的对象
  2. 然后至少有一个日期(fromto
  3. 的对象
  4. 最后没有任何
  5. 的对象

    日期本身并不重要,只是它们的存在。在Ruby中我可以这样做(如果日期是nil我将它设置为一个非常低的日期):

    date_ranges.sort { |a, b|
      [fix_nil(a.from), fix_nil(a.to)] <=> [fix_nil(b.from), fix_nil(b.to)]
    }.reverse
    
    def fix_nil(val)
      val.nil? ? Date.new(0) : val
    end
    

    使用Swift执行此操作的最佳方法是什么?提前谢谢。

3 个答案:

答案 0 :(得分:2)

似乎将dateCount计算属性添加到DateRange类型可能是个好主意。这将是模式匹配的好时机:

extension DateRange {
    // returns the number of non-nil NSDate members in 'from' and 'to'
    var dateCount: Int {
        switch (from, to) {
        case (nil, nil): return 0
        case (nil, _): return 1
        case (_, nil): return 1
        default: return 2
        }
    }
}

然后您可以使用简单的闭包对列表进行排序:

var ranges = [DateRange(nil, nil), DateRange(NSDate(), nil), DateRange(nil, NSDate()), DateRange(nil, nil), DateRange(NSDate(), NSDate())]
ranges.sort { $0.dateCount > $1.dateCount }

如果您愿意,您甚至可以使用更多行来Comparable

extension DateRange : Comparable { }
func ==(lhs: DateRange, rhs: DateRange) -> Bool {
    return lhs.dateCount == rhs.dateCount
}
func <(lhs: DateRange, rhs: DateRange) -> Bool {
    return lhs.dateCount > rhs.dateCount
}

这使您可以使用运算符参数正确对列表进行排序:

ranges.sort(<)

答案 1 :(得分:1)

我认为 list 是指 array ,所以我的答案基于这个假设。

您可以使用数组结构的sort方法,该方法采用具有此签名的闭包:

(lhs: T, rhs: T) -> Bool 
如果true小于lhs,则

返回rhs,否则返回false。

我想出了这个实现:

var x: [DateRange]
// ... initialize the array

x.sort { (lhs: DateRange, rhs: DateRange) -> Bool in
    if lhs.from != nil && lhs.to != nil {
        return true
    }

    if lhs.from == nil && lhs.to == nil {
        return false
    }

    return rhs.from == nil && rhs.to == nil
}
  • 如果lhs两个属性都不是nil,则无论rhs
  • ,它都是第一位的
  • 如果lhs的属性均为nil,则无论rhs
  • 如何
  • else lhs只有一个nil,另一个不是nil,在这种情况下,只有当rhs具有两个属性nil时它才会出现

如果您计划在多个地方重复使用sort,最好将代码移出sort方法 - 最佳位置可能是<运算符的重载:

func < (lhs: DateRange, rhs: DateRange) -> Bool {
    if lhs.from != nil && lhs.to != nil {
        return true
    }

    if lhs.from == nil && lhs.to == nil {
        return false
    }

    return rhs.from == nil && rhs.to == nil
}

在这种情况下,可以按如下方式使用:

x.sort(<)

如果您不喜欢运算符重载,您当然可以为该函数指定任何其他名称。

请注意,排序是到位

答案 2 :(得分:1)

以下是我将如何处理这个问题。为简单起见,请为日期范围添加评分函数。在您的方案中,您有3种可能性:

nil&amp;零:0分

nil&amp;日期:1分

日期&amp;日期:2分

import Foundation

class DateRange {
    var from: NSDate?
    var to: NSDate?

    init(from: NSDate?, to: NSDate?)
    {
        self.from = from
        self.to = to
    }

    func scoreDateRange() -> Int
    {
        var score = 0
        if from != nil
        {
            score++
        }
        if to != nil
        {
            score++
        }
        return score
    }
}

func sortDateRange( d1 : DateRange, d2 : DateRange)-> Bool
{

    return d1.scoreDateRange() > d2.scoreDateRange()
}

var date_ranges = [DateRange]()
date_ranges.append(DateRange(from:nil, to:nil))
date_ranges.append(DateRange(from:nil, to:nil))
date_ranges.append(DateRange(from:NSDate(), to:NSDate()))
date_ranges.append(DateRange(from:nil, to:NSDate()))
date_ranges.append(DateRange(from:NSDate(), to:nil))
date_ranges.append(DateRange(from:NSDate(), to:NSDate()))

date_ranges.sort(sortDateRange)
相关问题