List comprehension in Swift
语言指南没有显示任何列表理解的痕迹。用什么最简洁的方法来迅速完成这项工作?我在找类似的东西:
1 | evens = [ x for x in range(10) if x % 2 == 0] |
作为SWIFT。北部和东部,有一个短的列表的Python风格的理解。
最简单的适配(python的方程式是什么样的"读应用到一个变换序列受a过滤器"和"
1 2 3 4 5 6 7 | // 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 }) |
注意是一
1 2 3 4 | // 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中的列表(和其他一些语言中相似的结构),在后续行动迅速进行相同的语法为其他业务。这是,它的同一风格的语法构成,过滤器,和一系列的经营,因为它是数字滤波器阵列和经营上的对象-你不使用的功能的方法是在一个孩子/句法和语法的工作理解为一个列表。
你的护照和其他功能的
1 2 3 4 5 | // func isAwesome(person: Person) -> Bool // let people: [Person] let names = people.filter(isAwesome).sort(<).map({ $0.name }) let sum = (0..<10).reduce(0, combine: +) |
取决于你走,但有更简明的方式,可以说你的意思。例如,如果你想和偶整数列表,你可以使用
1 | let evenStride = 0.stride(to: 10, by: 2) // or stride(through:by:), to include 10 |
在这一类,那么你一发电机,所以你会想让
1 | let evensArray = Array(evenStride) // [0, 2, 4, 6, 8] |
编辑:案例研究迅速修订2。如果你想编辑历史湖1.x.斯威夫特
你可以选择一个敏捷5,一个样品的七阶码在以下游戏的解决你的问题。
# 1。使用
1 2 3 4 | let sequence = stride(from: 0, to: 10, by: 2) let evens = Array(sequence) // let evens = sequence.map({ $0 }) // also works print(evens) // prints [0, 2, 4, 6, 8] |
# 2。使用方法
1 2 3 | let range = 0 ..< 10 let evens = range.filter({ $0 % 2 == 0 }) print(evens) // prints [0, 2, 4, 6, 8] |
# 3。使用方法
1 2 3 | let range = 0 ..< 10 let evens = range.compactMap({ $0 % 2 == 0 ? $0 : nil }) print(evens) // prints [0, 2, 4, 6, 8] |
# 4。使用
1 2 3 4 5 6 | let unfoldSequence = sequence(first: 0, next: { $0 + 2 < 10 ? $0 + 2 : nil }) let evens = Array(unfoldSequence) // let evens = unfoldSequence.map({ $0 }) // also works print(evens) // prints [0, 2, 4, 6, 8] |
# 5。使用
1 2 3 4 5 6 7 8 9 10 | let anySequence = AnySequence<Int>({ () -> AnyIterator<Int> in var value = 0 return AnyIterator<Int> { defer { value += 2 } return value < 10 ? value : nil } }) let evens = Array(anySequence) // let evens = anySequence.map({ $0 }) // also works print(evens) // prints [0, 2, 4, 6, 8] |
# 6。在WHERE子句使用环
1 2 3 4 5 | var evens = [Int]() for value in 0 ..< 10 where value % 2 == 0 { evens.append(value) } print(evens) // prints [0, 2, 4, 6, 8] |
# 7。如果使用的是环状态
1 2 3 4 5 6 7 | var evens = [Int]() for value in 0 ..< 10 { if value % 2 == 0 { evens.append(value) } } print(evens) // prints [0, 2, 4, 6, 8] |
2你可以做为斯威夫特这样的东西:
1 2 3 4 5 6 7 | var evens = [Int]() for x in 1..<10 where x % 2 == 0 { evens.append(x) } // or directly filtering Range due to default implementations in protocols (now a method) let evens = (0..<10).filter{ $0 % 2 == 0 } |
通常,一个名单,可以理解在Python写的形式:
1 | [f(x) for x in xs if g(x)] |
这是相同的。
1 | map(f, filter(g, xs)) |
因此,你可以写它在斯威夫特
1 | listComprehension<Y>(xs: [X], f: X -> Y, g: X -> Bool) = map(filter(xs, g), f) |
例如:
1 | map(filter(0..<10, { $0 % 2 == 0 }), { $0 }) |
不得不承认,我很惊讶没有人提到平面图,因为我认为这是斯威夫特列出(或设置或听写)理解的最接近的事情。
1 2 3 | var evens = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].flatMap({num -> Int? in if num % 2 == 0 {return num} else {return nil} }) |
flatmap接受一个闭包,您可以返回单个值(在这种情况下,它将返回一个包含所有非nil值的数组并丢弃nil),也可以返回数组段(在这种情况下,它将把您的所有段关联在一起并返回该值)。
平面图似乎主要(总是?)无法推断返回值。当然,在这种情况下它不能,所以我把它指定为->in t?这样我就可以返回nils,从而丢弃奇数元素。
如果您愿意,可以嵌套平面图。我发现它们比地图和过滤器的组合更直观(虽然显然也有点局限)。例如,使用平面图,顶部答案的"Evens Squared"变为,
1 2 3 | var esquares = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].flatMap({num -> Int? in if num % 2 == 0 {return num * num} else {return nil} }) |
语法不完全是一行,与其他所有行都不完全相同。我不确定我是否喜欢这个(因为对于Python中的简单情况,它非常短,而且仍然非常可读)或者更多(因为复杂的情况可能会失控,并且经验丰富的Python程序员经常认为,当同一家公司的初学者需要半个小时来弄清楚什么内容时,它们是完全可读和可维护的。它本来是要做的,更不用说它实际在做什么了。)
这里是从中返回单个项目或零的平面图版本,这里是从中返回段的版本。
可能还值得同时查看array.map和array.foreach,因为它们都非常方便。
这个线程中没有提到的列表理解的一个方面是,您可以将它应用于多个列表的笛卡尔积。python中的示例:
1 | [x + y for x in range(1,6) for y in range(3, 6) if x % 2 == 0] |
…或者Haskell:
1 | [x+y | x <- [1..5], y <- [3..5], x `mod` 2 == 0] |
在swift中,2列表等效逻辑是
1 2 3 4 5 6 7 8 9 | list0 .map { e0 in list1.map { e1 in (e0, e1) } } .joined() .filter(f) .map(g) |
当输入中的列表数量增加时,我们必须增加嵌套级别。
我最近做了一个小图书馆来解决这个问题(如果你认为这是个问题的话)。下面是我的第一个例子,通过图书馆
1 | Array(1...5, 3...5, where: { n, _ in n % 2 == 0}) { $0 + $1 } |
在一篇博客文章中解释了基本原理(以及更多关于列表理解的内容)。
一个办法是:
1 2 3 4 | var evens: Int[]() for x in 0..<10 { if x%2 == 0 {evens += x} // or evens.append(x) } |
- 远程算子
- 阵列