2014-11-03 17 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