自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Swift 中如何進(jìn)行多重條件排序

開發(fā) 后端
本文中的方法與 Swift 沒有強(qiáng)關(guān)聯(lián)。你可以把它應(yīng)用到任何語(yǔ)言上。您可以改進(jìn)代碼,使其更通用,以支持所需的任何對(duì)象或?qū)傩裕覍⒋俗鳛槟木毩?xí)。如果你有什么有趣的發(fā)現(xiàn),你可以在 Twitter 上和我分享你的結(jié)果。我很想看到你的實(shí)踐。

[[399875]]

本文轉(zhuǎn)載自微信公眾號(hào)「Swift 社區(qū)」,作者喜歡Swift的小安子。轉(zhuǎn)載本文請(qǐng)聯(lián)系Swift 社區(qū)公眾號(hào)。

前言

在一個(gè)條件或者單個(gè)屬性上進(jìn)行排序非常簡(jiǎn)單, Swift 本身就有相關(guān)的功能。

下面是對(duì) int 數(shù)組進(jìn)行排序的例子:

  1. let numbers = [3, 5, 6, 1, 8, 2] 
  2.          
  3. let sortedNumbers = numbers.sorted { (lhs, rhs) in 
  4.     return lhs < rhs 
  5.  
  6. // [1, 2, 3, 5, 6, 8] 

但有時(shí)我們需要根據(jù)多個(gè)條件或?qū)傩詠磉M(jìn)行排序。為了演示這一點(diǎn),我們創(chuàng)建一個(gè)結(jié)構(gòu)體來作為示例。

這里我們有一個(gè)簡(jiǎn)單的 BlogPost 結(jié)構(gòu)體,它包含帖子標(biāo)題和兩個(gè)統(tǒng)計(jì)數(shù)據(jù),即瀏覽次數(shù)pageView和會(huì)話持續(xù)時(shí)間sessionDuration。

  1. struct BlogPost { 
  2.     let title: String 
  3.     let pageView: Int 
  4.     let sessionDuration: Double 

Sample 數(shù)據(jù):

  1. extension BlogPost { 
  2.     static var examples: [BlogPost] = [ 
  3.         BlogPost(title: "Alice", pageView: 1, sessionDuration: 3), 
  4.         BlogPost(title: "Peter", pageView: 1, sessionDuration: 2), 
  5.         BlogPost(title: "Kofi", pageView: 1, sessionDuration: 1), 
  6.         BlogPost(title: "Akosua", pageView: 5, sessionDuration: 2), 
  7.         BlogPost(title: "Abena", pageView: 4, sessionDuration: 10) 
  8.     ] 

如果您想查看哪些文章表現(xiàn)良好,可以按照瀏覽次數(shù)對(duì)它們直接進(jìn)行排序。但是很多帖子都不那么流行,頁(yè)面瀏覽量也一樣。在這種情況下,需要根據(jù)另一個(gè)條件或?qū)傩詠磉M(jìn)行進(jìn)一步的排序。

我們將在本文中討論這種多屬性排序。他們有各種各樣的方法來解決這個(gè)問題。我將展示沒有任何復(fù)雜概念的最基本的方法。一旦你了解了基本原理,你就可以隨心所欲地進(jìn)階了。

什么是多條件排序

多條件排序是指我們比較第一個(gè)條件的排序,只有當(dāng)?shù)谝粋€(gè)條件相等時(shí),我們才轉(zhuǎn)到下一個(gè)條件。我們這樣做直到找到一個(gè)不相等的條件。

偽代碼如下所示:

  1. let sortedObjects = objects.sorted { (lhs, rhs) in 
  2.     for (lhsCriteria, rhsCriteria) in [(lhsCrtria1, rhsCriteria1), (lhsCrtria2, rhsCriteria2), (lhsCrtria3, rhsCriteria3), ... , (lhsCrtriaN, rhsCriteriaN)] { // <1> 
  3.         if lhsCriteria == rhsCriteria { // <2> 
  4.             continue 
  5.         } 
  6.         return lhsCriteria < rhsCriteria // <3> 
  7.     } 

<1> 我們從最重要的一個(gè)(也就是第一個(gè))開始,循環(huán)遍歷條件列表。

<2> 如果這個(gè)順序條件相等,我們不能根據(jù)它來決定順序,就跳到下一個(gè)條件。

<3> 如果我們可以根據(jù)條件決定兩個(gè)對(duì)象之間的順序,我們就停止并返回結(jié)果。

如果你很難理解偽代碼,不用擔(dān)心。我不是一個(gè)偽代碼專業(yè)作家。下面的例子應(yīng)該更清楚一點(diǎn)。

按照兩個(gè)字段對(duì)object數(shù)組進(jìn)行排序

我們使用前面提到的場(chǎng)景,我們希望根據(jù)表現(xiàn)對(duì)BlogPost進(jìn)行排序。

我們的表現(xiàn)取決于頁(yè)面瀏覽次數(shù)pageView,如果瀏覽次數(shù)相同,我們?cè)倏磗essionDuration。

下面是上一個(gè)例子中用到的BlogPost結(jié)構(gòu)體和對(duì)應(yīng)的sample數(shù)據(jù)。

  1. struct BlogPost { 
  2.     let title: String 
  3.     let pageView: Int 
  4.     let sessionDuration: Double 
  5.  
  6. extension BlogPost { 
  7.     static var examples: [BlogPost] = [ 
  8.         BlogPost(title: "Alice", pageView: 1, sessionDuration: 3), 
  9.         BlogPost(title: "Peter", pageView: 1, sessionDuration: 2), 
  10.         BlogPost(title: "Kofi", pageView: 1, sessionDuration: 1), 
  11.         BlogPost(title: "Akosua", pageView: 5, sessionDuration: 2), 
  12.         BlogPost(title: "Abena", pageView: 4, sessionDuration: 10) 
  13.     ] 

我們衡量表現(xiàn)的方法可以翻譯成下面這樣的代碼:

  1. let popularPosts = BlogPost.examples.sorted { (lhs, rhs) in if lhs.pageView == rhs.pageView { // <1> return lhs.sessionDuration > rhs.sessionDuration } 
  2.  
  3.   return lhs.pageView > rhs.pageView // <2> 

<1>如果博客文章有相同的訪問次數(shù),我們使用訪問時(shí)間。

<2>如果訪問次數(shù)不相等,我們可以直接根據(jù)訪問次數(shù)來排序(我們使用降序)

排序的結(jié)果:

  1. [BlogPost(title: "Akosua", pageView: 5, sessionDuration: 2.0),  
  2. BlogPost(title: "Abena", pageView: 4, sessionDuration: 10.0),  
  3. BlogPost(title: "Alice", pageView: 1, sessionDuration: 3.0),  
  4. BlogPost(title: "Peter", pageView: 1, sessionDuration: 2.0),  
  5. BlogPost(title: "Kofi", pageView: 1, sessionDuration: 1.0)] 

按照多個(gè)字段對(duì)object數(shù)組進(jìn)行排序

不難發(fā)現(xiàn),根據(jù)兩個(gè)條件來排序非常簡(jiǎn)單。讓我們引入更多的條件。如果博客文章的表現(xiàn)相同,我們按照title排序。

添加更多的sample數(shù)據(jù):

  1. extension BlogPost { 
  2.     static var examples2: [BlogPost] = [ 
  3.         BlogPost(title: "Zoo", pageView: 5, sessionDuration: 2), 
  4.         BlogPost(title: "Alice", pageView: 1, sessionDuration: 3), 
  5.         BlogPost(title: "Peter", pageView: 1, sessionDuration: 2), 
  6.         BlogPost(title: "Kofi", pageView: 1, sessionDuration: 1), 
  7.         BlogPost(title: "Akosua", pageView: 5, sessionDuration: 2), 
  8.         BlogPost(title: "Abena", pageView: 4, sessionDuration: 10), 
  9.         BlogPost(title: "Angero", pageView: 1, sessionDuration: 2) 
  10.     ] 

兩個(gè)條件和三個(gè)條件沒什么區(qū)別,我們可以沿用相同的邏輯:

  1. let popularPosts = BlogPost.examples2.sorted { (lhs, rhs) in 
  2.     if lhs.pageView == rhs.pageView { 
  3.         if lhs.sessionDuration == rhs.sessionDuration { // <1> 
  4.             return lhs.title < rhs.title 
  5.         } 
  6.          
  7.         return lhs.sessionDuration > rhs.sessionDuration 
  8.     } 
  9.      
  10.     return lhs.pageView > rhs.pageView 

<1> 我們添加了另一個(gè)if來檢查博客文章是否具有相同的會(huì)話持續(xù)時(shí)間,如果它們具有相同的頁(yè)面瀏覽次數(shù)和會(huì)話持續(xù)時(shí)間,則按標(biāo)題對(duì)它們進(jìn)行排序。

排序結(jié)果:

  1. [BlogPost(title: "Akosua", pageView: 5, sessionDuration: 2.0), 
  2. BlogPost(title: "Zoo", pageView: 5, sessionDuration: 2.0), 
  3. BlogPost(title: "Abena", pageView: 4, sessionDuration: 10.0), 
  4. BlogPost(title: "Alice", pageView: 1, sessionDuration: 3.0), 
  5. BlogPost(title: "Angero", pageView: 1, sessionDuration: 2.0), 
  6. BlogPost(title: "Peter", pageView: 1, sessionDuration: 2.0), 
  7. BlogPost(title: "Kofi", pageView: 1, sessionDuration: 1.0)] 

問題

我們可以對(duì)兩個(gè)和三個(gè)條件使用相同的邏輯。這里唯一的問題是,條件越多,需要的嵌套就越多。

這是一個(gè)多條件的例子,可能會(huì)導(dǎo)致pyramid of doom。

  1. let popularPosts = BlogPost.examples2.sorted { (lhs, rhs) in 
  2.     if lhs.pageView == rhs.pageView { 
  3.         if lhs.sessionDuration == rhs.sessionDuration {  
  4.             if lhs.nextCriteria == rhs.nextCriteria {  
  5.                 if lhs.nextCriteria == rhs.nextCriteria {  
  6.                     .... 
  7.                 } 
  8.  
  9.                 ... 
  10.             } 
  11.  
  12.             ... 
  13.         } 
  14.          
  15.         return lhs.sessionDuration > rhs.sessionDuration 
  16.     } 
  17.      
  18.     return lhs.pageView > rhs.pageView 

按照N個(gè)字段對(duì)object數(shù)組進(jìn)行排序

為了避免 pyramid of doom, 我們?cè)倏纯粗暗膫未a:

  1. let sortedObjects = objects.sorted { (lhs, rhs) in 
  2.     for (lhsCriteria, rhsCriteria) in [(lhsCrtria1, rhsCriteria1), (lhsCrtria2, rhsCriteria2), (lhsCrtria3, rhsCriteria3), ... , (lhsCrtriaN, rhsCriteriaN)] { 
  3.         if lhsCriteria == rhsCriteria { 
  4.             continue 
  5.         } 
  6.  
  7.         return lhsCriteria < rhsCriteria 
  8.     } 

上面的代碼不是解決類似問題的唯一方式,不過關(guān)鍵思路是相似的。關(guān)鍵思路就是把多個(gè)條件打包到一個(gè)集合當(dāng)中去遍歷。

  1. extension BlogPost { 
  2.     static var examples2: [BlogPost] = [ 
  3.         BlogPost(title: "Zoo", pageView: 5, sessionDuration: 2), 
  4.         BlogPost(title: "Alice", pageView: 1, sessionDuration: 3), 
  5.         BlogPost(title: "Peter", pageView: 1, sessionDuration: 2), 
  6.         BlogPost(title: "Kofi", pageView: 1, sessionDuration: 1), 
  7.         BlogPost(title: "Akosua", pageView: 5, sessionDuration: 2), 
  8.         BlogPost(title: "Abena", pageView: 4, sessionDuration: 10), 
  9.         BlogPost(title: "Angero", pageView: 1, sessionDuration: 2) 
  10.     ] 
  11.  
  12. typealias AreInIncreasingOrder = (BlogPost, BlogPost) -> Bool // <1> 
  13.      
  14. let popularPosts = BlogPost.examples2.sorted { (lhs, rhs) in     
  15.     let predicates: [AreInIncreasingOrder] = [ // <2> 
  16.         { $0.pageView > $1.pageView }, 
  17.         { $0.sessionDuration > $1.sessionDuration}, 
  18.         { $0.title < $1.title } 
  19.     ] 
  20.      
  21.     for predicate in predicates { // <3> 
  22.         if !predicate(lhs, rhs) && !predicate(rhs, lhs) { // <4> 
  23.             continue // <5> 
  24.         } 
  25.          
  26.         return predicate(lhs, rhs) // <5> 
  27.     } 
  28.      
  29.     return false 

<1>我聲明了一個(gè)別名 AreInIncreasingOrder 用來匹配排序閉包,這提高了我們對(duì)謂詞集合聲明的可讀性

<2> 我們聲明了一個(gè)謂詞集合

<3> 我們遍歷這個(gè)謂詞集合

<4> 這里是關(guān)鍵邏輯,我們想要檢查條件是否能決定博文順序。但是 AreInIncreasingOrder 返回了一個(gè)布爾值. 我們應(yīng)該如何判斷他們是否相等? 在回答這個(gè)問題之前,我們先檢查一下 AreInIncreasingOrder 的定義。

AreInIncreasingOrder 是一個(gè)謂詞,他會(huì)在第一個(gè)參數(shù)能決定順序時(shí)返回 true 否則返回 false 。兩個(gè)變量只有在各自都不是升序時(shí)才相等。

這意味著無(wú)論我們的參數(shù)順序如何,謂詞都必須是 false。換言之 lhs.pageView < rhs.pageView 和 rhs.pageView < lhs.pageView必須等于false才能決定順序相等。這就是我們 !predicate(lhs, rhs) && !predicate(rhs, lhs) 這句代碼的意思。

<5> 如果順序相等,那么 continue 到下一個(gè)謂詞。

<6> 如果順序不相等,那么我們可以用這個(gè)謂詞來排序。

排序結(jié)果:

  1. [BlogPost(title: "Akosua", pageView: 5, sessionDuration: 2.0),  
  2. BlogPost(title: "Zoo", pageView: 5, sessionDuration: 2.0),  
  3. BlogPost(title: "Abena", pageView: 4, sessionDuration: 10.0),  
  4. BlogPost(title: "Alice", pageView: 1, sessionDuration: 3.0),  
  5. BlogPost(title: "Angero", pageView: 1, sessionDuration: 2.0),  
  6. BlogPost(title: "Peter", pageView: 1, sessionDuration: 2.0), 
  7. BlogPost(title: "Kofi", pageView: 1, sessionDuration: 1.0)] 

結(jié)語(yǔ)

最近,我遇到了這個(gè)問題,覺得很有趣。這是一項(xiàng)簡(jiǎn)單的任務(wù),不過需要我花些時(shí)間去掌握。

 

本文中的方法與 Swift 沒有強(qiáng)關(guān)聯(lián)。你可以把它應(yīng)用到任何語(yǔ)言上。您可以改進(jìn)代碼,使其更通用,以支持所需的任何對(duì)象或?qū)傩?,我將此作為您的練?xí)。如果你有什么有趣的發(fā)現(xiàn),你可以在 Twitter 上和我分享你的結(jié)果。我很想看到你的實(shí)踐。

 

責(zé)任編輯:武曉燕 來源: Swift 社區(qū)
相關(guān)推薦

2010-02-01 18:20:17

Python 多重繼承

2011-08-22 12:05:50

Linux

2020-04-06 14:50:43

MySQLSQL數(shù)據(jù)庫(kù)

2013-02-21 10:32:29

Win Server 災(zāi)難恢復(fù)虛擬機(jī)

2023-12-11 08:25:15

Java框架Android

2010-06-02 14:16:18

SVN版本控制

2023-03-24 16:18:08

微服務(wù)架構(gòu)

2010-02-03 13:55:51

Python 代碼

2010-07-21 14:17:07

Linux telne

2010-09-13 10:45:04

2011-07-28 14:07:30

2023-09-03 23:49:35

2010-07-22 10:58:49

batch Telne

2013-01-28 10:11:24

敏捷設(shè)計(jì)敏捷開發(fā)

2017-07-28 11:31:59

iOS結(jié)構(gòu)優(yōu)化項(xiàng)目

2009-12-08 11:34:40

WCF Windows

2010-02-01 10:21:36

Python編碼轉(zhuǎn)換

2010-02-22 16:05:40

Python配置

2013-10-17 23:12:12

Windows 8.1Windows 8.1

2021-08-26 10:05:31

APP安全加密網(wǎng)絡(luò)攻擊
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)