生活随笔
收集整理的這篇文章主要介紹了
Swift之深入解析如何进行多重条件排序
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、前言
- 在一個條件或者單個屬性上進行排序非常簡單, Swift 本身就有相關的功能。
- 如下所示,對 int 數組進行排序的例子:
let numbers
= [3, 5, 6, 1, 8, 2]
let sortedNumbers
= numbers
.sorted
{ (lhs
, rhs
) inreturn lhs
< rhs
}
- 但有時需要根據多個條件或屬性來進行排序,那么該怎么處理呢?為了演示這一點,我們可以創建一個結構體來說明。如下所示,現有一個簡單的 BlogPost 結構體,它包含帖子標題和兩個統計數據,即瀏覽次數 pageView 和會話持續時間 sessionDuration:
struct BlogPost {let title
: Stringlet pageView
: Intlet sessionDuration
: Double
}
extension BlogPost {static var examples
: [BlogPost] = [BlogPost(title
: "Alice", pageView
: 1, sessionDuration
: 3),BlogPost(title
: "Peter", pageView
: 1, sessionDuration
: 2),BlogPost(title
: "Kofi", pageView
: 1, sessionDuration
: 1),BlogPost(title
: "Akosua", pageView
: 5, sessionDuration
: 2),BlogPost(title
: "Abena", pageView
: 4, sessionDuration
: 10)]
}
- 如果想查看哪些文章表現良好,可以按照瀏覽次數對它們直接進行排序,但是很多帖子都不那么流行,頁面瀏覽量也一樣。在這種情況下,需要根據另一個條件或屬性來進行進一步的排序。下面來分析一下多屬性排序,它們有各種各樣的方法來解決這個問題,這里只展示沒有任何復雜概念的最基本的方法,一旦了解了基本原理,就可以隨心所欲地進階。
二、多條件排序
- 多條件排序是指比較第一個條件的排序,只有當第一個條件相等時,才轉到下一個條件,直到找到一個不相等的條件。
- 偽代碼如下所示:
let sortedObjects
= objects
.sorted
{ (lhs
, rhs
) infor (lhsCriteria
, rhsCriteria
) in [(lhsCrtria1
, rhsCriteria1
), (lhsCrtria2
, rhsCriteria2
), (lhsCrtria3
, rhsCriteria3
), ... , (lhsCrtriaN
, rhsCriteriaN
)] { if lhsCriteria
== rhsCriteria
{ continue}return lhsCriteria
< rhsCriteria
}
}
-
- ① 從最重要的一個(也就是第一個)開始,循環遍歷條件列表;
-
- ② 如果這個順序條件相等,不能根據它來決定順序,就跳到下一個條件;
-
- ③ 如果可以根據條件決定兩個對象之間的順序,就停止并返回結果。
三、按照兩個字段對 object 數組進行排序
- 使用前面提到的場景,我們希望根據表現對 BlogPost 進行排序,表現取決于頁面瀏覽次數 pageView,如果瀏覽次數相同,再看 sessionDuration。
- 如下所示,是上一個例子中用到的 BlogPost 結構體和對應的 sample 數據:
struct BlogPost {let title
: Stringlet pageView
: Intlet sessionDuration
: Double
}extension BlogPost {static var examples
: [BlogPost] = [BlogPost(title
: "Alice", pageView
: 1, sessionDuration
: 3),BlogPost(title
: "Peter", pageView
: 1, sessionDuration
: 2),BlogPost(title
: "Kofi", pageView
: 1, sessionDuration
: 1),BlogPost(title
: "Akosua", pageView
: 5, sessionDuration
: 2),BlogPost(title
: "Abena", pageView
: 4, sessionDuration
: 10)]
}
let popularPosts
= BlogPost.examples
.sorted
{ (lhs
, rhs
) in if lhs
.pageView
== rhs
.pageView
{ return lhs
.pageView
> rhs
.pageView
}
-
-
- ② 如果訪問次數不相等,可以直接根據訪問次數來排序(使用降序)。
- 排序的結果:
[BlogPost(title
: "Akosua", pageView
: 5, sessionDuration
: 2.0),
BlogPost(title
: "Abena", pageView
: 4, sessionDuration
: 10.0),
BlogPost(title
: "Alice", pageView
: 1, sessionDuration
: 3.0),
BlogPost(title
: "Peter", pageView
: 1, sessionDuration
: 2.0),
BlogPost(title
: "Kofi", pageView
: 1, sessionDuration
: 1.0)]
四、按照多個字段對 object 數組進行排序
- 不難發現,根據兩個條件來排序非常簡單,讓我們引入更多的條件,如果博客文章的表現相同,按照 title 排序,添加更多的 sample 數據:
extension BlogPost {static var examples2
: [BlogPost] = [BlogPost(title
: "Zoo", pageView
: 5, sessionDuration
: 2),BlogPost(title
: "Alice", pageView
: 1, sessionDuration
: 3),BlogPost(title
: "Peter", pageView
: 1, sessionDuration
: 2),BlogPost(title
: "Kofi", pageView
: 1, sessionDuration
: 1),BlogPost(title
: "Akosua", pageView
: 5, sessionDuration
: 2),BlogPost(title
: "Abena", pageView
: 4, sessionDuration
: 10),BlogPost(title
: "Angero", pageView
: 1, sessionDuration
: 2)]
}
- 兩個條件和三個條件沒什么區別,可以沿用相同的邏輯:
let popularPosts
= BlogPost.examples2
.sorted
{ (lhs
, rhs
) inif lhs
.pageView
== rhs
.pageView
{if lhs
.sessionDuration
== rhs
.sessionDuration
{ return lhs
.title
< rhs
.title
} return lhs
.sessionDuration
> rhs
.sessionDuration
}return lhs
.pageView
> rhs
.pageView
}
[BlogPost(title
: "Akosua", pageView
: 5, sessionDuration
: 2.0),BlogPost(title
: "Zoo", pageView
: 5, sessionDuration
: 2.0),BlogPost(title
: "Abena", pageView
: 4, sessionDuration
: 10.0),BlogPost(title
: "Alice", pageView
: 1, sessionDuration
: 3.0),BlogPost(title
: "Angero", pageView
: 1, sessionDuration
: 2.0),BlogPost(title
: "Peter", pageView
: 1, sessionDuration
: 2.0),BlogPost(title
: "Kofi", pageView
: 1, sessionDuration
: 1.0)]
- 可以對兩個和三個條件使用相同的邏輯,這里唯一的問題是,條件越多,需要的嵌套就越多。如下所示,這是一個多條件的例子,可能會導致 pyramid of doom:
let popularPosts
= BlogPost.examples2
.sorted
{ (lhs
, rhs
) inif lhs
.pageView
== rhs
.pageView
{if lhs
.sessionDuration
== rhs
.sessionDuration
{ if lhs
.nextCriteria
== rhs
.nextCriteria
{ if lhs
.nextCriteria
== rhs
.nextCriteria
{ ....}...}...} return lhs
.sessionDuration
> rhs
.sessionDuration
}return lhs
.pageView
> rhs
.pageView
}
五、按照 N 個字段對 object 數組進行排序
- 為了避免 pyramid of doom,再看看之前的偽代碼:
let sortedObjects
= objects
.sorted
{ (lhs
, rhs
) infor (lhsCriteria
, rhsCriteria
) in [(lhsCrtria1
, rhsCriteria1
), (lhsCrtria2
, rhsCriteria2
), (lhsCrtria3
, rhsCriteria3
), ... , (lhsCrtriaN
, rhsCriteriaN
)] {if lhsCriteria
== rhsCriteria
{continue}return lhsCriteria
< rhsCriteria
}
}
- 上面的代碼不是解決類似問題的唯一方式,不過關鍵思路是相似的,關鍵思路就是把多個條件打包到一個集合當中去遍歷:
extension BlogPost {static var examples2
: [BlogPost] = [BlogPost(title
: "Zoo", pageView
: 5, sessionDuration
: 2),BlogPost(title
: "Alice", pageView
: 1, sessionDuration
: 3),BlogPost(title
: "Peter", pageView
: 1, sessionDuration
: 2),BlogPost(title
: "Kofi", pageView
: 1, sessionDuration
: 1),BlogPost(title
: "Akosua", pageView
: 5, sessionDuration
: 2),BlogPost(title
: "Abena", pageView
: 4, sessionDuration
: 10),BlogPost(title
: "Angero", pageView
: 1, sessionDuration
: 2)]
}typealias AreInIncreasingOrder = (BlogPost, BlogPost) -> Bool let popularPosts
= BlogPost.examples2
.sorted
{ (lhs
, rhs
) in let predicates
: [AreInIncreasingOrder] = [ { $0.pageView
> $1.pageView
},{ $0.sessionDuration
> $1.sessionDuration
},{ $0.title
< $1.title
}]for predicate
in predicates
{ if !predicate(lhs
, rhs
) && !predicate(rhs
, lhs
) { continue }return predicate(lhs
, rhs
) }return false
}
- 分析說明:
-
- ① 聲明一個別名 AreInIncreasingOrder 用來匹配排序閉包,這可以提高對謂詞集合聲明的可讀性;
-
-
-
- ④ 這里是關鍵邏輯,想要檢查條件是否能決定博文順序,但是 AreInIncreasingOrder 返回了一個布爾值,我們應該如何判斷它們是否相等? 先來看看定義,AreInIncreasingOrder 是一個謂詞,它會在第一個參數能決定順序時返回 true 否則返回 false,兩個變量只有在各自都不是升序時才相等;這意味著無論參數順序如何,謂詞都必須是 false,換言之 lhs.pageView < rhs.pageView 和 rhs.pageView < lhs.pageView 必須等于 false 才能決定順序相等,這就是 !predicate(lhs, rhs) && !predicate(rhs, lhs) 這句代碼的意思;
-
- ⑤ 如果順序相等,那么 continue 到下一個謂詞;
-
- 排序結果:
[BlogPost(title
: "Akosua", pageView
: 5, sessionDuration
: 2.0), BlogPost(title
: "Zoo", pageView
: 5, sessionDuration
: 2.0), BlogPost(title
: "Abena", pageView
: 4, sessionDuration
: 10.0), BlogPost(title
: "Alice", pageView
: 1, sessionDuration
: 3.0), BlogPost(title
: "Angero", pageView
: 1, sessionDuration
: 2.0), BlogPost(title
: "Peter", pageView
: 1, sessionDuration
: 2.0),BlogPost(title
: "Kofi", pageView
: 1, sessionDuration
: 1.0)]
總結
以上是生活随笔為你收集整理的Swift之深入解析如何进行多重条件排序的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。