本文转载自微信公众号《Swift社区》。笔者喜欢Swift中的小安子。如需转载本文,请联系Swift社区公众号。前言对条件或单个属性进行排序非常简单,Swift本身也有相关的功能。下面是对一个int数组进行排序的例子:letnumbers=[3,5,6,1,8,2]letsortedNumbers=numbers.sorted{(lhs,rhs)inreturnlhsiflhsCriteria==rhsCriteria{//<2>continue}returnlhsCriteria}}<1>我们从最重要的(也就是第一个)开始,循环遍历条件列表。<2>如果顺序条件相等,则无法据此确定顺序,跳转到下一个条件。<3>如果我们可以根据条件决定两个对象之间的顺序,我们就停止并返回结果。如果您很难理解伪代码,请不要担心。我不是伪代码的专业作者。下面的例子应该会更清楚一点。按两个字段对对象数组进行排序我们使用前面提到的场景,我们希望按性能对BlogPost进行排序。我们的性能取决于页面浏览量pageView,如果浏览量相同,我们就看sessionDuration。以下是上一示例中使用的BlogPost结构和相应的示例数据。structBlogPost{lettitle:StringletpageView:IntletsessionDuration:Double}extensionBlogPost{staticvarexamples:[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)]}我们衡量性能的方法可以转化为这样的代码:letpopularPosts=BlogPost.examples.sorted{(lhs,rhs)iniflhs.pageView==rhs.pageView{//<1>returnlhs.sessionDuration>rhs.sessionDuration}returnlhs.pageView>rhs.pageView//<2>}<1>如果博文的访问量相同,我们使用访问时间。<2>如果访问次数不相等,我们可以直接按照访问次数对结果进行排序(我们使用降序):[BlogPost(title:"Akosua",pageView:5,sessionDuration:2.0),BlogPost(标题:“Abena”,pageView:4,sessionDuration:10.0),BlogPost(标题:“Alice”,pageView:1,sessionDuration:3.0),BlogPost(标题:“Peter”,pageView:1,sessionDuration:2.0),BlogPost(title:"Kofi",pageView:1,sessionDuration:1.0)]对象数组按多个字段排序不难发现,按两个条件排序很简单。让我们再介绍一些条件。如果博客文章具有相同的表现,我们按标题排序。添加更多示例数据:extensionBlogPost{staticvarexamples2:[BlogPost]=[BlogPost(title:"Zoo",pageView:5,sessionDuration:2),BlogPost(title:"Alice",pageView:1,sessionDuration:3),BlogPost(标题:“Peter”,pageView:1,sessionDuration:2),BlogPost(标题:“Kofi”,pageView:1,sessionDuration:1),BlogPost(标题:“Akosua”,pageView:5,sessionDuration:2),BlogPost(title:"Abena",pageView:4,sessionDuration:10),BlogPost(title:"Angero",pageView:1,sessionDuration:2)]}两个条件和三个条件没有区别,我们可以用同一个逻辑:letpopularPosts=BlogPost.examples2.sorted{(lhs,rhs)iniflhs.pageView==rhs.pageView{iflhs.sessionDuration==rhs.sessionDuration{//<1>returnlhs.titlerhs.sessionDuration}returnlhs.pageView>rhs.pageView}<1>我们添加了另一个if来检查博客帖子是否具有相同的会话持续时间,以及它们是否具有相同的浏览量和会话持续时间,然后按标题对它们进行排序。排序结果:[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)]问题我们可以对两个和三个条件使用相同的逻辑。这里唯一的问题是条件越多,越需要嵌套。这是可能导致厄运金字塔的多种情况的示例。letpopularPosts=BlogPost.examples2.sorted{(lhs,rhs)iniflhs.pageView==rhs.pageView{iflhs.sessionDuration==rhs.sessionDuration{iflhs.nextCriteria==rhs.nextCriteria{iflhs.nextCriteria==rhs.nextCriteria{....}...}...}returnlhs.sessionDuration>rhs.sessionDuration}returnlhs.pageView>rhs.pageView}将对象数组按照N个字段排序为了避免pyramidofdoom,我们看前面的伪代码:letsortedObjects=objects.sorted{(lhs,rhs)infor(lhsCriteria,rhsCriteria)in[(lhsCrtria1,rhsCriteria1),(lhsCrtria2,rhsCriteria2),(lhsCrtria3,rhsCriteria3),...,(lhsCrtriaN,rhsCriteriaN)]{iflhsCriteria==rhsCriteria{continue}returnlhsCriteriaBool//<1>letpopularPosts=BlogPost.examples2.排序{(lhs,rhs)inletpredicates:[AreInIncreasingOrder]=[//<2>{$0.pageView>$1.pageView},{$0.sessionDuration>$1.sessionDuration},{$0.title<$1.title}]forpredicateinpredicates{//<3>if!predicate(lhs,rhs)&&!predicate(rhs,lhs){//<4>继续//<5>}returnpredicate(lhs,rhs)//<5>}returnfalse<1>我声明了一个别名AreInIncreasingOrder用于匹配排序闭包,提高我们谓词集声明的可读性<2>我们声明一个谓词集<3>我们遍历这个谓词集<4>这里是关键逻辑,我们要检查的条件是可以确定后订单,但AreInIncreasingOrder返回一个布尔值。我们如何检查它们是否相等?在回答这个问题之前,我们先看看AreInIncreasingOrder的定义。AreInIncreasingOrder是一个谓词,如果第一个参数确定顺序则返回true,否则返回false。只有当两个变量都不按升序排列时,两个变量才相等。这意味着无论我们论证的顺序如何,谓词都必须为假。换句话说,lhs.pageView如果顺序相等,则继续下一个谓词。<6>如果顺序不相等,那么我们可以使用这个谓词来排序。排序结果:[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没有强相关性。您可以将其应用于任何语言。您可以改进代码使其更通用以支持您想要的任何对象或属性,我将此作为练习留给您。如果你发现任何有趣的事情,你可以在Twitter上与我分享你的结果。我很想在实践中见到你。