给swift程序猿留下深刻印象的10个Swift代码

通过使用单行代码完成同样的 10 个练习,我们来看看 Swift 和其他语言之间的较量。

  

  将数组中每个元素的值乘以 2

使用map来实现

        var arr = [1,2,3,4];
        var newArr = arr.map{$0*2}
        for item in newArr
        {
            print(item)
        }

代码简单明了地完成了数组元素乘2

  求一组数字的和

  这个问题可以通过使用 reduce 方法和加号运算符解决,这是因为加号运算符实际上也是一个函数。不过这个解法是非常显而易见的,待会儿我们会看到 reduce 方法更具有创造力的使用。

        var arr = [1,2,3,4];

        let sum = arr.reduce(0, combine: +)

        print(sum)

检索字符串中含有某个单词

我们使用 contains方法判断一个字符串中是否至少含有一个被选中的关键字:

        let arr = ["ForrestWoo","Swift1"]
        let str = "My name is ForrestWoo,I am learning Swift"
        let query = arr.contains(str.containsString)
        print(query)

  读取一个文件


    let path = NSBundle.mainBundle().pathForResource("filter", ofType: "rtf")

        let lines = try? String(contentsOfFile: path!).characters.split{$0 == "\n"}.map(String.init)

        for item in lines! {

            print(item)

        }


  祝你生日快乐

        let name = "Forrest"
        (1...4).forEach{print("Happy Birthday " + (($0 == 3) ? "dear \(name)":"to You"))}

这段代码会将“祝你生日快乐”这首歌的歌词输出到控制台中,它在一段区间内简单的使用了 map 函数,同时也用到了三元运算符。

  数组过滤

假设我们需要使用一个给定的过滤函数将一个序列(sequence)分割为两部分。很多语言除了有常规的mapflatMapreducefilter 等函数外,还有一个 partitionBy 函数恰好可以完成这个需求。正如你所知,Swift 没有类似的函数(我们不想在这里使用 NSArray 中的函数,并通过NSPredicate 实现过滤功能)。

所以,我们可以通过拓展 SequenceType,并为它添加 partitionBy 函数来解决这个问题。我们使用这个函数将整数数组分割为两部分:

extension SequenceType{
    typealias Element = Self.Generator.Element

    func partitionBy(fu: (Element)->Bool)->([Element],[Element]){
        var first=[Element]()
        var second=[Element]()
        for el in self {
            if fu(el) {
                first.append(el)
            }else{
                second.append(el)
            }
        }
        return (first,second)
    }
}

let part = [82, 58, 76, 49, 88, 90].partitionBy{$0 < 60}
part // ([58, 49], [82, 76, 88, 90])

实际上,这不是单行代码,而且使用了命令式的解法。能不能使用 filter 对它略作改进呢?

extension SequenceType{

    func anotherPartitionBy(fu: (Self.Generator.Element)->Bool)->([Self.Generator.Element],[Self.Generator.Element]){
        return (self.filter(fu),self.filter({!fu($0)}))
    }
}

let part2 = [82, 58, 76, 49, 88, 90].anotherPartitionBy{$0 < 60}
part2 // ([58, 49], [82, 76, 88, 90])

这种解法略好一些,但是他遍历了序列两次。而且为了用单行代码实现,我们删除了闭合函数,这会导致很多重复的内容(过滤函数和数组会在两处被用到)。

能不能只用单个数据流就对原来的序列进行转换,把两个部分分别存入一个元组中呢?答案是是可以的,使用 reduce 方法:

var part3 = [82, 58, 76, 49, 88, 90].reduce( ([],[]), combine: {
    (a:([Int],[Int]),n:Int) -> ([Int],[Int]) in
    (n<60) ? (a.0+[n],a.1) : (a.0,a.1+[n])
})
part3 // ([58, 49], [82, 76, 88, 90])

这里我们创建了一个用于保存结果的元组,它包含两个部分。然后依次取出原来序列中的元素,根据过滤结果将它放到第一个或第二个部分中。

我们终于用真正的单行代码解决了这个问题。不过有一点需要注意,我们使用 append 方法来构造两个部分的数组,所以这实际上比前两种实现慢一些。

  获取并解析 XML 格式的网络服务

上述的某些语言不需要依赖外部的库,而且默认有不止一种方案可以处理 XML 格式的数据(比如 Scala 自身就可以将 XML 解析成对象,尽管实现方法比较笨拙),但是 (Swift 的)Foundation 库仅提供了 SAX 解析器,叫做 NSXMLParser。你也许已经猜到了:我们不打算使用这个。

在这种情况下,我们可以选择一些开源的库。这些库有的用 C 实现,有的用 Objective-C 实现,还有的是纯 Swift 实现。

这次,我们打算使用纯 Swift 实现的库:AEXML:

let xmlDoc = try? AEXMLDocument(xmlData: NSData(contentsOfURL: NSURL(string:"https://www.ibiblio.org/xml/examples/shakespeare/hen_v.xml")!)!)

if let xmlDoc=xmlDoc {
    var prologue = xmlDoc.root.children[6]["PROLOGUE"]["SPEECH"]
    prologue.children[1].stringValue // Now all the youth of England are on fire,
    prologue.children[2].stringValue // And silken dalliance in the wardrobe lies:
    prologue.children[3].stringValue // Now thrive the armourers, and honour‘s thought
    prologue.children[4].stringValue // Reigns solely in the breast of every man:
    prologue.children[5].stringValue // They sell the pasture now to buy the horse,
}

  找到数组中最小(或最大)的元素

我们有多种方式求出 sequence 中的最大和最小值,其中一种方式是使用 minElement 和maxElement 函数:

//Find the minimum of an array of Ints
[10,-22,753,55,137,-1,-279,1034,77].sort().first
[10,-22,753,55,137,-1,-279,1034,77].reduce(Int.max, combine: min)
[10,-22,753,55,137,-1,-279,1034,77].minElement()

//Find the maximum of an array of Ints
[10,-22,753,55,137,-1,-279,1034,77].sort().last
[10,-22,753,55,137,-1,-279,1034,77].reduce(Int.min, combine: max)
[10,-22,753,55,137,-1,-279,1034,77].maxElement()

  

  并行处理

某些语言支持用简单透明的方式允许对序列的并行处理,比如使用 map 和 flatMap 这样的函数。这使用了底层的线程池,可以加速多个依次执行但又彼此独立的操作。

Swift 还不具备这样的特性,但我们可以用 GCD 实现:

http://moreindirection.blogspot.it/2015/07/gcd-and-parallel-collections-in-swift.html

  

  埃拉托色尼选筛法

古老而优秀的埃拉托色尼选筛法被用于找到所有小于给定的上限 n 的质数。

首先将所有小于 n 的整数都放入一个序列(sequence)中,这个算法会移除每个数字的倍数,直到剩下的所有数字都是质数。为了加快执行速度,我们其实不必检查每一个数字的倍数,当检查到 n 的平方根时就可以停止。

基于以上定义,最初的实现可能是这样的:

var n = 50
var primes = Set(2...n)

(2...Int(sqrt(Double(n)))).forEach{primes.subtractInPlace((2*$0).stride(through:n, by:$0))}
primes.sort()

在外层的区间里,我们遍历每一个需要检查的数字。对于每一个数字,我们使用stride(through:Int by:Int) 函数计算出由它的倍数构成的序列。最初,我们用所有 2 到 n 的整数构造了一个集合(Set),然后从集合中减掉每一个生成的序列中的元素。

不过正如你所见,为了真正的删除掉这些倍数,我们使用了一个外部的可变集合,这会带来副作用。

我们总是应该尝试消除副作用,所以我们先计算所有的子序列,然后调用 flatMap 方法将其中所有的元素展开,存放到单个数组中,最后再从原始的集合中删除这些整数。

var sameprimes = Set(2...n)

sameprimes.subtractInPlace((2...Int(sqrt(Double(n))))
                           .flatMap{ (2*$0).stride(through:n, by:$0)})
sameprimes.sort()

  使用析构交换元组中的值

既然是福利,自然并非每个人都知道这一点。和其他具有元组类型的语言一样,Swift 的元组可以被用来交换两个变量的值,代码很简洁:

var a=1,b=2

(a,b) = (b,a)
a //2
b //1

以上就是全部内容,正如我们预料的那样,Swift 和其他语言一样富有表现力。

时间: 2024-10-08 15:24:49

给swift程序猿留下深刻印象的10个Swift代码的相关文章

程序猿们,快用Emoji表情写代码吧

Emoji表情真是无所不能了.你知道它能当密码,但你想过它能用来编程吗?国外论坛4Chan的一位网友就把Emoji变成了编程语言. 这门语言名为FourMan,它当然有一个表情名称,但抱歉,我正在用的编辑框打不出来啊!看看题图中的例子,你能猜出写的什么吗?大概是编程累成狗吧.不知道程序猿看到这种语言作何感想? FourMan还处于早期阶段,制作者只是开发了一些示例代码,制定了语言规范,但它的最终目标是开发出编译器,Android,iOS和Windows Phone版的IDEs,以及能使用表情的键

连载《一个程序猿的生命周期》-10.在项目中忍受病魔的折磨

2009年是俺的本命年,人家都说本命年十有八九都不是太好,我也未能幸免.从年初开始,感觉身体就特别虚弱,打篮球跑会儿就会感觉特别累,这种情况还在进一步恶化,比我想象的要严重的多. 这一年也是我参加工作的第三个年头,有了理论基础,有了扎实的技术,正是要施展拳脚的时候.我是有强烈意愿.目标和报复的人,也是脚踏实地干事的人,在这一年,不管在工作上,还是在身体上,都面临着严峻的挑战和考验. 3月初的时候,得到A城市有一个集团数据集成的项目,大概4月中旬就要去现场.以前也亲自参与过数据集成的项目,干的是一

程序猿之---C语言细节10(++操作很可能你会出错)

主要内容:++操作细节 #include <stdio.h> int main(int argc, char** argv) { int t1 = 2, t2 = 0; //t2 = t1++ + t1++; // 在语句结束后才执行两个++,结果t2 = 4 t2 = t1++ > 0? t1++:t1; // 这里直接在?判断完之后执行了一次++操作,结果t2 = 3 printf("t2 = %d\n",t2); return 0; } 结果:

C#程序员经常用到的10个实用代码片段

1 读取操作系统和CLR的版本 OperatingSystem os = System.Environment.OSVersion; Console.WriteLine("Platform: {0}", os.Platform); Console.WriteLine("Service Pack: {0}", os.ServicePack); Console.WriteLine("Version: {0}", os.Version); Consol

C#程序员经常用到的10个实用代码片段 - 操作系统

原文地址  如果你是一个C#程序员,那么本文介绍的10个C#常用代码片段一定会给你带来帮助,从底层的资源操作,到上层的UI应用,这些代码也许能给你的开发节省不少时间.以下是原文: 1 读取操作系统和CLR的版本 1 OperatingSystem os = System.Environment.OSVersion; 2 Console.WriteLine("Platform: {0}", os.Platform); 3 Console.WriteLine("Service P

资深程序猿冒死揭开软件潜规则:无法维护的代码

原始博文公布于: Roedy Green's Mindproducts (http://mindprod.com/unmain.html ). 翻译链接: 点击打开链接 2014年11月25日 03:11 怎样编写无法维护的代码 让自己稳拿铁饭碗 ;-) Roedy Green 简单介绍 永远不要(把自己遇到的问题)归因于(他人的)恶意,这恰恰说明了(你自己的)无能. -- 拿破仑 为了造福大众,在Java编程领域创造就业机会,兄弟我在此传授大师们的秘籍.这些大师写的代码极其难以维护.后继者就是

一个平凡但不平庸的程序猿2018个人总结

前言 又到了一年一度的年终总结了,相信大家估计也开始写总结,本人也不例外.在公司中写完模板化的总结之后,自己还是写了一个给自己的总结.本篇总结主要是讲述去年所定下目标的完成情况和人生感悟以及明年的目标. 去年目标以及完成情况 去年目标 完整的链接在这里:一个两年java程序猿的2017个人总结 这里先列举一下去年定的目标: 阅读2本以上的技术相关书籍,并作出相应的实践: 阅读5本以上国内外有意思的书籍: 阅读jdk常用类的源码,能够理解其中的涵义: 能够熟练掌握3个常用的技术框架: 继续坚持每天

疯狂Java学习笔记(72)-----------大话程序猿面试

大话程序猿面试 10个我最喜欢问程序猿的面试问题 程序猿面试不全然指南 10个经典的C语言面试基础算法及代码 程序猿的10大成功面试技巧 程序猿选择公司的8个标准 编程开发 8个值得关注的PHP安全函数 简析TCP的三次握手与四次分手 10分钟掌握XML.JSON及其解析 高效的jQuery代码编写技巧总结 编译器的工作过程和原理 CPU空暇时在"忙"什么 5个强大的Java分布式缓存框架推荐 架构设计 趣味漫画:云计算的起源 负载均衡调度算法大全 程序人生 程序猿不不过写代码 201

挨踢部落故事汇(18):程序猿与代码的基情

"朋友,你还会修电脑啊?"这是小史在朋友中听到过的最多的一句话.每当听到这句话时,他也很无奈.难道程序猿就一定要会修电脑嘛?但是没办法,在朋友眼中,编程是一个很高深的工作.可能动动手指,哪边就会出什么事,生活十分精彩.嗯,电影看多了.作为一名不会修电脑但努力想学习修电脑的程序猿来说,除了修电脑的技能,也还要具备大部分其他程序猿共有的特质.比如:宅.闷.可能也具备独有的特质,喜欢陪老婆逛街... 小史·Java开发 严肃的简单介绍下本期主人公小史童鞋,从事Java后台开发工作已经三年有余