2014-11-03 88 views
5

我有一个Swift对象列表,我想按照多个条件排序。在列表中的对象是DateRange类型:如何按多个条件排序Swift对象

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

列表包含许多对象,其中一些fromto字段是零的。我想有这个名单排序:

  1. 先说有至少有一个日期(无论是fromto
  2. 而在最后的对象没有任何
  3. 日期
  4. 然后对象的所有对象

日期本身并不重要,只是它们的存在。在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 

做什么用斯威夫特做到这一点的最好方法是什么?提前致谢。

回答

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(<) 
+0

用于模式匹配的很好用例,感谢您的帮助! – 2014-11-04 19:30:21

1

我相信,通过列表你的意思是阵列,所以我立足于这个假设我的答案。

可以使用阵列结构的sort方法,该方法具有该签名的闭合:

(lhs: T, rhs: T) -> Bool 

返回true如果lhs小于rhs,否则返回假。

我想出了这样实现:

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有没有零这两个属性,那么它是第一位的,无论rhs
  • 如果lhs有两个属性为零,那么如果之后来到,不管rhs
  • 否则lhs有一个零,其他不为零,在这种情况下它只有在rhs具有两个属性无

如果你打算重用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(<) 

如果你不喜欢操作符重载,你当然可以给予该函数任何其他名称。

请注意,排序完成到位

+0

我认为你的比较有一个错误 - 当比较两个相同的'DateRange'实例(如果它们都是'(nil,nil)')时,这将返回true。 – 2014-11-04 02:28:53

+0

如果lhs同时为零,则返回false – Antonio 2014-11-04 08:28:59

+0

对不起 - 我把它弄倒了。如果两个范围都有日期,那么这将返回true,因为第一个条件只查看'lhs'。 – 2014-11-04 15:12:27

1

下面是我将如何处理这个问题。为了简单起见,请为日期范围添加评分功能。在你的情况,你有3种可能性:

零&零:0分

零&日期:1点

日期&日期: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) 
+0

用得分功能的好主意,谢谢你的快速回答! – 2014-11-04 19:29:37