Як повернути перші 5 об’єктів масиву в Swift?


179

Чи є у Swift розумний спосіб використання методів вищого порядку в Array для повернення 5 перших об'єктів? Спосіб obj-c - це збереження індексу, і for-loop через індекс збільшення масиву, поки він не став 5, і повернення нового масиву. Чи є спосіб це зробити filter, mapабо reduce?


Дивіться мою відповідь на Swift 4, який показує до 6 різних способів повернення перших nелементів Array.
Imanou Petit

Відповіді:


445

На сьогодні найменший спосіб отримати перші N елементів масиву Swift 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))


42
+1 такий невірний вибір імені, IMHO. У масиву є, dropFirstі dropLastтак може бути takeFirstі takeLast.
Мазюд

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

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

2
@ onmyway133 prefix, можливо, є лише Swift 2.x (я не пам'ятаю, чи був він у 1.x), але він, безумовно, є в будь-якій ОС, яка підтримує Swift 2.x, а саме iOS 7 і вище. Доступність функції Swift визначається випусками Swift, а не версіями iOS.
mluisbrown

99

Оновлення: тепер є можливість використовувати prefixдля отримання перших n елементів масиву. Перевірте відповідь @ mluisbrown для пояснення, як використовувати префікс.

Оригінал Відповідь: Ви можете зробити це дуже легко без filter, mapабо 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

4
Він зазнає краху, якщо у wholeArrayнього не буде більше елементів, ніжn
Джейк Лін

@Crashalot Я не зовсім впевнений, але думаю, що тоді, де я написав свою відповідь, такого не було prefix.
Крістіан

1
Використовуйте цей код, щоб отримати перші 5 об'єктів ... Це прекрасно працює [0,1,2,3,4,5] .enumerated (). FlatMap {$ 0 <5? $ 1: нуль}
Маніш Махаджан

64

З Swift 5, відповідно до ваших потреб, ви можете вибрати один із 6 наступних кодів ігрового майданчика , щоб вирішити свою проблему.


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

Apple заявляє про 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"]

Apple заявляє про 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

1
Дякую! У випадку, якщо ви хочете оновити, flatMap тепер називається compactMap у Swift 4 для ущільнення масиву.
manmal

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

Я трохи змінив відповідь Маркуса, щоб оновити її для останньої версії Swift, оскільки varвсередині вашої декларації методу більше не підтримується:

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

3

Швидкий 4

Для отримання перших N елементів масиву Swift ви можете використовувати prefix(_ maxLength: Int):

Array(largeArray.prefix(5))

1

Swift 4 із збереженням типів масивів

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

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()]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.