วิธีการคืนค่า 5 วัตถุแรกของ Array ใน Swift


179

ใน Swift มีวิธีที่ชาญฉลาดในการใช้วิธีการเรียงลำดับที่สูงขึ้นใน Array เพื่อส่งคืนวัตถุแรก 5 ตัวหรือไม่ วิธี obj-c ในการทำมันคือการบันทึกดัชนีและ for-loop ผ่านดัชนีการเพิ่มอาร์เรย์จนกว่ามันจะเป็น 5 และส่งคืนอาร์เรย์ใหม่ มีวิธีการทำเช่นนี้กับfilter, mapหรือreduce?


ดูคำตอบของฉันสำหรับสวิฟท์ 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
Mazyod

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łomiejSemań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
Jake Lin

@Crashalot ฉันไม่แน่ใจว่าทั้งหมด prefixแต่ฉันคิดว่าในเวลาที่ฉันได้เขียนคำตอบของฉันไม่มีสิ่งดังกล่าวเป็น
คริสเตียน

1
ใช้รหัสนี้เพื่อรับวัตถุ 5 ชิ้นแรก ... ใช้งานได้อย่างสมบูรณ์แบบ [0,1,2,3,4,5] .enumerated (). flatMap {$ 0 <5? $ 1: ไม่มี}
Manish Mahajan

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


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]คุณทำเช่นนี้

ในการเลือกองค์ประกอบแรกของอาร์เรย์ให้มีฟังก์ชั่นและใช้งานได้มากขึ้นคุณสามารถสร้างวิธีการขยายสำหรับการทำมันได้ ตัวอย่างเช่น

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

ในการรับองค์ประกอบ 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

อัปเดตสำหรับ swift 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) คุณวนซ้ำองค์ประกอบทั้งหมด
Alexander Bekert

2
10000? นั่นอะไร?
BangOperator

1

ธรรมดาและเรียบง่าย

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

1

สำหรับอาร์เรย์ของวัตถุคุณสามารถสร้างส่วนขยายจากลำดับ

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()]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.