如何在Swift中返回Array的前5个对象?


176

在Swift中,是否有聪明的方法在Array上使用高阶方法来返回5个第一个对象?obj-c的操作方式是保存索引,并通过循环递增数组递增索引直到索引为5并返回新数组。有没有办法做到这一点filtermap或者reduce


请参阅我对Swift 4的回答,其中显示了多达6种不同的方法来返回的第一个n元素Array
Imanou Petit

Answers:


434

到目前为止,获取Swift数组的前N个元素的最简洁的方法是使用prefix(_ maxLength: Int)

let someArray = [1, 2, 3, 4, 5, 6, 7]
let first5 = someArray.prefix(5) // 1, 2, 3, 4, 5

这样具有边界安全的好处。如果传递给您的计数prefix大于数组计数,则它仅返回整个数组。

注意:注释中所指出的,Array.prefix实际上返回ArraySlice,而不是Array。在大多数情况下,这没有什么区别,但是如果您需要将结果分配给Array类型或将其传递给期望Array参数的方法,则需要将结果强制为Array类型:let first5 = Array(someArray.prefix(5))


40
+1这样的坏名字选择,恕我直言。数组具有dropFirstand dropLast,因此也可能具有takeFirstand takeLast
Mazyod 2015年

10
此外,如果你需要first5是一个数组,只写let first5 = Array(someArray.prefix(5))
ULazdins

2
@mluisbrown对不起,不能同意您的意见:)在我video = video.prefix(5)的Xcode 7.2 项目中导致编译错误 Cannot assign value of type 'ArraySlice<Video>' to type '[Video]'
ULazdins 2015年

5
video = Array(video.prefix(5))
巴特洛梅耶Semańczyk

2
@ onmyway133 prefix可能仅是Swift 2.x(我不记得它是否在1.x中),但是它肯定存在于所有支持Swift 2.x的OS(iOS 7及更高版本)中。Swift功能的可用性取决于Swift版本,而不是iOS版本。
mluisbrown '16

98

更新: 现在可以用来prefix获取数组的前n个元素。检查@mluisbrown的答案以获取有关如何使用前缀的说明。

原始答案: 如果没有filtermap或者reduce仅返回数组范围,您可以非常轻松地完成此操作:

var wholeArray = [1, 2, 3, 4, 5, 6]
var n = 5

var firstFive = wholeArray[0..<n] // 1,2,3,4,5

71
如果只n需要Swift数组中的第一个项目,则可以这样做wholeArray.prefix(n),它具有边界安全的额外好处。如果n大于数组大小,则prefix返回整个数组。
mluisbrown 2015年

4
如果wholeArray元素数不超过,它将崩溃n
杰克·林

@Crashalot我不太确定,但我认为当时我写的答案不存在prefix
基督教徒

1
使用此代码获取前5个对象...可以完美工作 [0,1,2,3,4,5] .enumerated()。flatMap {$ 0 <5?$ 1:nil}
Manish Mahajan '18

63

使用Swift 5,可以根据需要选择以下6种Playground代码之一来解决您的问题。


#1。使用subscript(_:)下标

let array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]
let arraySlice = array[..<5]
//let arraySlice = array[0..<5] // also works
//let arraySlice = array[0...4] // also works
//let arraySlice = array[...4] // also works
let newArray = Array(arraySlice)
print(newArray) // prints: ["A", "B", "C", "D", "E"]

#2。使用prefix(_:)方法

复杂度:如果集合符合,则为O(1)RandomAccessCollection;否则为O(k),其中k是要从集合的开头选择的元素数。

let array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]
let arraySlice = array.prefix(5)
let newArray = Array(arraySlice)
print(newArray) // prints: ["A", "B", "C", "D", "E"]

苹果声明prefix(_:)

如果最大长度超过集合中元素的数量,则结果将包含集合中的所有元素。


#3。使用prefix(upTo:)方法

复杂度:O(1)

let array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]
let arraySlice = array.prefix(upTo: 5)
let newArray = Array(arraySlice)
print(newArray) // prints: ["A", "B", "C", "D", "E"]

苹果声明prefix(upTo:)

使用该prefix(upTo:)方法等效于使用部分半开范围作为集合的下标。下标表示法优先于prefix(upTo:)


#4。使用prefix(through:)方法

let array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]
let arraySlice = array.prefix(through: 4)
let newArray = Array(arraySlice)
print(newArray) // prints: ["A", "B", "C", "D", "E"]

#5。使用removeSubrange(_:)方法

复杂度:O(n),其中n是集合的长度。

var array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]
array.removeSubrange(5...)
print(array) // prints: ["A", "B", "C", "D", "E"]

#6。使用dropLast(_:)方法

复杂度:如果集合符合,则为O(1)RandomAccessCollection;否则为O(k),其中k是要删除的元素数。

let array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]
let distance = array.distance(from: 5, to: array.endIndex)
let arraySlice = array.dropLast(distance)
let newArray = Array(arraySlice)
print(newArray) // prints: ["A", "B", "C", "D", "E"]

28
let a: [Int] = [0, 0, 1, 1, 2, 2, 3, 3, 4]
let b: [Int] = Array(a.prefix(5))
// result is [0, 0, 1, 1, 2]

18

SWIFT 4

不同的解决方案:

一个简单的内联解决方案,如果阵列太短,则不会崩溃

[0,1,2,3,4,5].enumerated().compactMap{ $0.offset < 3 ? $0.element : nil }

但是可以正常工作。

[0,1,2,3,4,5].enumerated().compactMap{ $0.offset < 1000 ? $0.element : nil }

如果这样做,通常会崩溃:

[0,1,2,3,4,5].prefix(upTo: 1000) // THIS CRASHES

[0,1,2,3,4,5].prefix(1000) // THIS DOESNT

3
对于swift3[0,1,2,3,4,5].enumerated().flatMap{ $0.offset < 1000 ? $0.element : nil }
StevenTsooo '16

1
谢谢!如果要更新,在Swift 4中,flatMap现在被称为compactMap,用于数组压缩。
manmal '18

14

为了获得数组的前5个元素,您需要做的就是对有问题的数组进行切片。在Swift中,您可以这样操作:array[0..<5]

为了使数组的N个前元素更具功能性和通用性,您可以创建一个扩展方法来实现。例如:

extension Array {
    func takeElements(var elementCount: Int) -> Array {
        if (elementCount > count) {
            elementCount = count
        }
        return Array(self[0..<elementCount])
    }
}

5

我略微更改了Markus的答案以将其更新为最新的Swift版本,因为var不再支持您的方法声明内:

extension Array {
    func takeElements(elementCount: Int) -> Array {
        if (elementCount > count) {
            return Array(self[0..<count])
        }
        return Array(self[0..<elementCount])
    }
}

3

斯威夫特4

要获取Swift数组的前N个元素,您可以使用prefix(_ maxLength: Int)

Array(largeArray.prefix(5))


1

快速更新4:

[0,1,2,3,4,5].enumerated().compactMap{ $0 < 10000 ? $1 : nil }

快速3:

[0,1,2,3,4,5].enumerated().flatMap{ $0 < 10000 ? $1 : nil }

1
无效的解决方案。1)您创建一个数组长度的附加序列。2)您遍历所有元素。
亚历山大·贝克尔

2
10000?那是什么?
BangOperator

1

简单明了

extension Array {
    func first(elementCount: Int) -> Array {
          let min = Swift.min(elementCount, count)
          return Array(self[0..<min])
    }
}

1

对于对象数组,可以从Sequence创建扩展。

extension Sequence {
    func limit(_ max: Int) -> [Element] {
        return self.enumerated()
            .filter { $0.offset < max }
            .map { $0.element }
    }
}

用法:

struct Apple {}

let apples: [Apple] = [Apple(), Apple(), Apple()]
let limitTwoApples = apples.limit(2)

// limitTwoApples: [Apple(), Apple()]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.