在Swift中列出理解

Mar*_*ina 43 list-comprehension swift

语言指南没有透露列表理解的痕迹.在Swift中实现这一目标的最佳方法是什么?我正在寻找类似的东西:

evens = [ x for x in range(10) if x % 2 == 0]
Run Code Online (Sandbox Code Playgroud)

ric*_*ter 59

从Swift 2.x开始,Python样式列表理解有一些简短的等价物.

Python的公式的最直接的调整(其内容类似于"应用转换到一个序列受到过滤器")涉及的链接mapfilter方法适用于所有SequenceTypeS,并从开始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 })
Run Code Online (Sandbox Code Playgroud)

请注意,a Range是抽象的 - 它实际上并不创建您要求它的整个值列表,只是一个懒惰地按需提供它们的构造.(在这个意义上它更像是Python xrange.)然而,filter调用返回一个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 })
Run Code Online (Sandbox Code Playgroud)

与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: +)
Run Code Online (Sandbox Code Playgroud)

但是,根据您的目标,可能会有更简洁的方式来表达您的意思.例如,如果您特别需要偶数整数列表,则可以使用stride:

let evenStride = 0.stride(to: 10, by: 2) // or stride(through:by:), to include 10
Run Code Online (Sandbox Code Playgroud)

与范围一样,这会让你成为一个生成器,因此你需要从中创建一个Array或者遍历它以查看所有值:

let evensArray = Array(evenStride) // [0, 2, 4, 6, 8]
Run Code Online (Sandbox Code Playgroud)

编辑:严重修改Swift 2.x. 如果您想要Swift 1.x,请参阅编辑历史记录.

  • 您还可以避免使用`Array(filter(1..10){$ 0%2 == 0})`创建一个中间数组 (4认同)

Ima*_*tit 7

使用Swift 5,您可以选择以下七个Playground示例代码中的一个来解决您的问题.


#1.使用stride(from:to:by:)功能

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]
Run Code Online (Sandbox Code Playgroud)

#2.使用Range filter(_:)方法

let range = 0 ..< 10
let evens = range.filter({ $0 % 2 == 0 })
print(evens) // prints [0, 2, 4, 6, 8]
Run Code Online (Sandbox Code Playgroud)

#3.使用Range compactMap(_:)方法

let range = 0 ..< 10
let evens = range.compactMap({ $0 % 2 == 0 ? $0 : nil })
print(evens) // prints [0, 2, 4, 6, 8]
Run Code Online (Sandbox Code Playgroud)

#4.使用sequence(first:next:)功能

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]
Run Code Online (Sandbox Code Playgroud)

#5.使用AnySequence init(_:)初始化程序

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]
Run Code Online (Sandbox Code Playgroud)

#6.使用for子句的for循环

var evens = [Int]()
for value in 0 ..< 10 where value % 2 == 0 {
    evens.append(value)
}
print(evens) // prints [0, 2, 4, 6, 8]
Run Code Online (Sandbox Code Playgroud)

#7.在if条件下使用for循环

var evens = [Int]()
for value in 0 ..< 10 {
    if value % 2 == 0 {
        evens.append(value)
    }
}
print(evens) // prints [0, 2, 4, 6, 8]
Run Code Online (Sandbox Code Playgroud)