Swift'te Array'ın ilk 5 nesnesini nasıl geri getirebilirim?


179

Swift'te, ilk 5 nesneyi döndürmek için Array'da daha yüksek dereceli yöntemleri kullanmanın akıllıca bir yolu var mı? Bunu yapmanın obj-c yolu, bir indeksi kaydetme ve 5 olana kadar dizi artış indeksi arasında geçiş yapma ve yeni diziyi döndürmektir. Bunu yapmanın bir yolu var mı filter, mapyoksa reduce?


Swift'in ilk nöğelerini döndürmenin 6 farklı yolunu gösteren cevabımı görün Array.
Imanou Petit

Yanıtlar:


445

Bir Swift dizisinin ilk N elemanını elde etmenin en güzel yolu aşağıdakileri kullanıyor prefix(_ maxLength: Int):

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

Bunun güvenli sınırlar olma avantajı vardır. Eğer geçmek sayımı ise prefixdizi sayısı daha büyüktür o zaman sadece bütün dizi döndürür.

NOT: yorumlarda belirtildiği gibi, Array.prefixaslında bir ArraySlicedeğil, bir döndürür Array. Çoğu durumda bu bir fark yaratmamalıdır, ancak sonucu bir Arraytüre atamanız veya bir Arrayparametre bekleyen bir yönteme aktarmanız gerekiyorsa, sonucu bir Arraytüre zorlamanız gerekir :let first5 = Array(someArray.prefix(5))


42
+1 böyle kötü bir isim seçimi, IMHO. Dizi sahiptir dropFirstve dropLastbu yüzden de sahip olabilir takeFirstve takeLast.
Mazyod

10
Ayrıca first5bir dizi olması gerekiyorsa , sadece yazmaklet first5 = Array(someArray.prefix(5))
ULazdins

2
@mluisbrown Üzgünüm, sizinle aynı fikirde değilim :) video = video.prefix(5)Xcode Cannot assign value of type 'ArraySlice<Video>' to type '[Video]'
7.2'deki projemde

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

2
@ onmyway133 prefixmuhtemelen sadece Swift 2.x ( 1.x'te olup olmadığını hatırlamıyorum), ancak kesinlikle iOS 7 ve üstü olan Swift 2.x'i destekleyen herhangi bir işletim sisteminde var. Swift özelliğinin kullanılabilirliği, iOS sürümlerine göre Swift sürümlerine göre belirlenir.
mluisbrown

99

Güncelleme: Artık prefixbir dizinin ilk n öğesini almak için kullanma imkanı var . Ön ekin nasıl kullanılacağına ilişkin bir açıklama için @ mluisbrown'un cevabını kontrol edin .

Orijinal Cevap: Sen gerçekten kolay olmadan yapabilir filter, mapya da reducesadece dizinin bir dizi döndürerek:

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

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

71
Eğer nbir Swift dizisinin sadece ilk öğeleri istiyorsanız, wholeArray.prefix(n)hangi sınır güvenli olmanın avantajı vardır yapabilirsiniz . Eğer ndizi boyutu daha büyük prefixgeri dönüş tam dizi.
mluisbrown

4
Daha wholeArrayfazla unsuru yoksa n
Jake Lin

@Crashalot Tamamen emin değilim, ama sanırım o zaman, cevabımı yazdığım yerde böyle bir şey yoktu prefix.
Hristiyan

1
İlk 5 nesneyi almak için bu kodu kullanın ... Bu mükemmel bir şekilde çalışır [0,1,2,3,4,5] .enumerated (). FlatMap {$ 0 <5? 1 $: Nil}
Manish Mahajan

64

Swift 5 ile, ihtiyaçlarınıza göre, sorununuzu çözmek için aşağıdaki 6 Oyun Alanı kodundan birini seçebilirsiniz .


# 1. Alt subscript(_:)simge kullanma

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(_:)Yöntemi kullanarak

Karmaşıklık: O (1) eğer toplama uygunsa RandomAccessCollection; aksi takdirde O ( k ); burada k , koleksiyonun başından itibaren seçilecek öğe sayısıdır.

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 şunları belirtiyor prefix(_:):

Maksimum uzunluk koleksiyondaki öğe sayısını aşarsa, sonuç koleksiyondaki tüm öğeleri içerir.


3.. prefix(upTo:)Yöntemi kullanarak

Karmaşıklık: 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 şunları belirtiyor prefix(upTo:):

Kullanma prefix(upTo:)yöntemi koleksiyonun en alt yazı olarak kısmi bir yarı açık aralığı kullanarak eşdeğerdir. Alt simge gösterimi tercih edilir prefix(upTo:).


4.. prefix(through:)Yöntemi kullanarak

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(_:)Yöntemi kullanarak

Karmaşıklık: O ( n ); burada n , koleksiyonun uzunluğudur.

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(_:)Yöntemi kullanarak

Karmaşıklık: O (1) eğer toplama uygunsa RandomAccessCollection; aksi takdirde, O ( k ), burada k bırakılacak eleman sayısıdır.

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

Farklı bir çözüm:

Diziniz çok kısasa çökmeyecek kolay bir satır içi çözüm

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

Ama bununla iyi çalışıyor.

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

Bunu yaparsanız genellikle bu çökecektir:

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

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

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

1
Teşekkürler! Güncellemek istediğinizde, flatMap artık dizi sıkıştırması için Swift 4'te compactMap olarak adlandırılıyor.
manmal

14

Bir dizinin ilk 5 öğesini elde etmek için tek yapmanız gereken söz konusu diziyi dilimlemek. Swift, sen böyle yapmak: array[0..<5].

Bir dizinin N öğesinin seçimini biraz daha işlevsel ve genelleştirilebilir hale getirmek için, bunu yapmak için bir uzantı yöntemi oluşturabilirsiniz. Örneğin:

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

5

varYöntem beyanınızın içinde artık desteklenmediği için Markus'un yanıtını en son Swift sürümü için güncellemek için biraz değiştirdim :

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

3

Hızlı 4

Bir Swift dizisinin ilk N öğesini almak için şunları kullanabilirsiniz prefix(_ maxLength: Int):

Array(largeArray.prefix(5))

1

Dizi türlerini kaydeden Swift 4

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

1

Hızlı 4 için güncelleme:

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

Hızlı 3 için:

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

1
Etkisiz çözüm. 1) Bir dizi için ek uzunluk dizisi oluşturursunuz. 2) Tüm unsurları tekrarlıyorsunuz.
Alexander Bekert

2
10000? Bu da ne?
BangOperator

1

Sade ve Basit

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

1

Bir dizi nesne için Sıradan bir uzantı oluşturabilirsiniz.

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

Kullanımı:

struct Apple {}

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

// limitTwoApples: [Apple(), Apple()]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.