Làm cách nào để trả về 5 đối tượng đầu tiên của Array trong Swift?


178

Trong Swift, có cách nào thông minh để sử dụng các phương thức bậc cao hơn trên Array để trả về 5 đối tượng đầu tiên không? Cách làm obj-c là lưu chỉ mục và vòng lặp for thông qua chỉ số tăng mảng cho đến khi 5 và trả về mảng mới. Có cách nào để làm điều này với filter, maphoặc reduce?


Xem câu trả lời của tôi cho Swift 4 hiển thị tối đa 6 cách khác nhau để trả về các nphần tử đầu tiên của an Array.
Imanou Petit

Câu trả lời:


440

Cho đến nay, cách gọn gàng nhất để có được các phần tử N đầu tiên của mảng Swift đang sử dụng prefix(_ maxLength: Int):

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

Điều này có lợi ích là giới hạn an toàn. Nếu số đếm bạn chuyển đến prefixlớn hơn số mảng thì nó chỉ trả về toàn bộ mảng.

LƯU Ý: như được chỉ ra trong các ý kiến, Array.prefixthực sự trả về một ArraySlice, không phải một Array. Trong hầu hết các trường hợp, điều này không tạo ra sự khác biệt nhưng nếu bạn cần gán kết quả cho một Arrayloại hoặc chuyển nó sang một phương thức mong đợi một thông số, Arraybạn sẽ cần buộc kết quả thành một Arrayloại:let first5 = Array(someArray.prefix(5))


41
+1 lựa chọn tên xấu như vậy, IMHO. Mảng có dropFirstdropLast, vì vậy cũng có thể có takeFirsttakeLast.
Mazyod

10
Ngoài ra nếu bạn cần first5phải là một mảng, chỉ cần viếtlet first5 = Array(someArray.prefix(5))
ULazdins

2
@mluisbrown Xin lỗi, không thể đồng ý với bạn :) Trong dự án của tôi video = video.prefix(5)trong Xcode 7.2 dẫn đến lỗi biên dịch Cannot assign value of type 'ArraySlice<Video>' to type '[Video]'
ULazdins

5
video = Array(video.prefix(5))
Bartłomiej Semańchot

2
@ onmyway133 prefixchỉ có thể là Swift 2.x (Tôi không nhớ nếu nó ở 1.x), nhưng nó chắc chắn tồn tại trong bất kỳ HĐH nào hỗ trợ Swift 2.x, là iOS 7 trở lên. Tính khả dụng của tính năng Swift được xác định bởi các bản phát hành Swift, không phải phiên bản iOS.
mluisbrown

99

Cập nhật: Bây giờ có khả năng sử dụng prefixđể có được n phần tử đầu tiên của một mảng. Kiểm tra câu trả lời của @ mluisbrown để biết giải thích cách sử dụng tiền tố.

Original Trả lời: Bạn có thể làm điều đó thực sự dễ dàng mà không cần filter, maphoặc reducebằng cách chỉ trả lại một loạt các mảng của bạn:

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

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

71
Nếu bạn chỉ muốn các nmục đầu tiên từ một mảng Swift, bạn có thể làm điều wholeArray.prefix(n)đó có thêm lợi ích là giới hạn an toàn. Nếu nlớn hơn kích thước mảng prefixtrả về toàn bộ mảng.
mluisbrown

4
Nó sẽ sụp đổ nếu wholeArraykhông có nhiều yếu tố hơnn
Jake Lin

@Crashalot Tôi không hoàn toàn chắc chắn, nhưng tôi nghĩ vào thời điểm đó, nơi tôi đã viết câu trả lời của mình, không có điều gì như vậy prefix.
Christian

1
Sử dụng mã này để nhận 5 đối tượng đầu tiên ... Điều này hoạt động hoàn hảo [0,1,2,3,4,5] .enumerated (). FlatMap {$ 0 <5? $ 1: nil}
Manish Mahajan

64

Với Swift 5, theo nhu cầu của bạn, bạn có thể chọn một trong 6 mã Playground sau để giải quyết vấn đề của mình.


# 1. Sử dụng subscript(_:)chỉ mục

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. Sử dụng prefix(_:)phương pháp

Độ phức tạp: O (1) nếu bộ sưu tập phù hợp với RandomAccessCollection; mặt khác, O ( k ), trong đó k là số phần tử được chọn từ đầu bộ sưu tập.

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"]

Apple tuyên bố prefix(_:):

Nếu độ dài tối đa vượt quá số phần tử trong bộ sưu tập, kết quả chứa tất cả các phần tử trong bộ sưu tập.


# 3. Sử dụng prefix(upTo:)phương pháp

Độ phức tạp: 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"]

Apple tuyên bố prefix(upTo:):

Sử dụng prefix(upTo:)phương thức này tương đương với việc sử dụng phạm vi nửa mở một phần làm chỉ mục của bộ sưu tập. Các ký hiệu đăng ký được ưa thích hơn prefix(upTo:).


#4. Sử dụng prefix(through:)phương pháp

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. Sử dụng removeSubrange(_:)phương pháp

Độ phức tạp: O ( n ), trong đó n là chiều dài của bộ sưu tập.

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. Sử dụng dropLast(_:)phương pháp

Độ phức tạp: O (1) nếu bộ sưu tập phù hợp với RandomAccessCollection; mặt khác, O ( k ), trong đó k là số phần tử được thả.

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

Chuyển 4

Một giải pháp khác nhau:

Một giải pháp nội tuyến dễ dàng không bị sập nếu mảng của bạn quá ngắn

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

Nhưng hoạt động tốt với điều này.

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

Thông thường điều này sẽ sụp đổ nếu bạn làm điều này:

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

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

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

1
Cảm ơn! Trong trường hợp bạn muốn cập nhật, FlatMap hiện được gọi là compactMap trong Swift 4 để nén mảng.
manody

14

Để có được 5 phần tử đầu tiên của một mảng, tất cả những gì bạn cần làm là cắt mảng đó trong câu hỏi. Trong Swift, bạn làm như thế này : array[0..<5].

Để làm cho việc chọn N phần tử đầu tiên của một mảng có nhiều chức năng và khái quát hơn, bạn có thể tạo một phương thức mở rộng để thực hiện nó. Ví dụ:

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

5

Tôi đã thay đổi một chút câu trả lời của Markus để cập nhật nó cho phiên bản Swift mới nhất, vì varbên trong khai báo phương thức của bạn không còn được hỗ trợ:

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

3

Swift 4

Để có được các phần tử N đầu tiên của mảng Swift, bạn có thể sử dụng prefix(_ maxLength: Int):

Array(largeArray.prefix(5))

1

Swift 4 với các kiểu mảng lưu

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

1

Cập nhật cho swift 4:

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

Đối với nhanh chóng 3:

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

1
Giải pháp không hiệu quả. 1) Bạn tạo thêm chuỗi độ dài của một mảng. 2) Bạn lặp qua tất cả các yếu tố.
Alexander Bekert

2
10000? Cái gì vậy
BangOperator

1

Đồng bằng & đơn giản

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

1

Đối với một mảng các đối tượng, bạn có thể tạo một phần mở rộng từ Sequence.

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

Sử dụng:

struct Apple {}

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

// limitTwoApples: [Apple(), Apple()]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.