一尘不染

Swift中的列表理解

swift

语言指南显示没有列表理解的痕迹。 在Swift中完成这项工作的最简洁的方法是什么? 我正在寻找类似的东西:

evens = [ x for x in range(10) if x % 2 == 0]

阅读 244

收藏
2020-07-07

共1个答案

一尘不染

从Swift 2.x开始,Python样式列表理解有一些简短的等效内容。

Python公式的最直接的改编(读取类似“将转换应用于要过滤的序列”之类的东西)包括将可用于所有s
mapfilter方法链接起来SequenceType,并从以下位置开始Range

// Python: [ x for x in range(10) if x % 2 == 0 ]
let evens = (0..<10).filter { $0 % 2 == 0 }

// Another example, since the first with 'x for x' doesn't
// use the full ability of a list comprehension:
// Python: [ x*x for x in range(10) if x % 2 == 0 ]
let evenSquared = (0..<10).filter({ $0 % 2 == 0 }).map({ $0 * $0 })

请注意,a Range是抽象的-
它实际上不会创建您要求的值的完整列表,而只是按需延迟提供它们的构造。(从这种意义上讲,它更像是Python的xrange。)但是,该filter调用返回an
Array,因此您在那里失去了“惰性”方面。如果您想让收藏一直保持懒散,请这样说:

// Python: [ x for x in range(10) if x % 2 == 0 ]
let evens = (0..<10).lazy.filter { $0 % 2 == 0 }
// Python: [ x*x for x in range(10) if x % 2 == 0 ]
let evenSquared = (0..<10).lazy.filter({ $0 % 2 == 0 }).map({ $0 * $0 })

与Python中的列表理解语法(以及某些其他语言中的类似构造)不同,Swift中的这些操作遵循与其他操作相同的语法。也就是说,构造,过滤和操作一系列数字的语法与过滤和操作对象数组的语法是同一样式-
您不必为一种工作使用函数/方法语法并列出另一个语法。

您可以将其他函数传递给filtermap调用,并链接其他方便的转换,例如sortreduce

// func isAwesome(person: Person) -> Bool
// let people: [Person]
let names = people.filter(isAwesome).sort(<).map({ $0.name })

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

但是,根据您要做什么,可能会有更简洁的方式表达您的意思。例如,如果您特别想要偶数列表,则可以使用stride

let evenStride = 0.stride(to: 10, by: 2) // or stride(through:by:), to include 10

与范围一样,它可以为您提供一个生成器,因此您需要从中生成一个Array或对其进行遍历以查看所有值:

let evensArray = Array(evenStride) // [0, 2, 4, 6, 8]

编辑: 对Swift 2.x进行了重大修订。如果需要Swift 1.x,请参阅编辑历史记录。

2020-07-07