วิธีที่ถูกต้องในการค้นหาค่าสูงสุดใน Array ใน Swift


121

จนถึงตอนนี้ฉันมีวิธีง่ายๆ (แต่อาจมีราคาแพง):

var myMax = sort(myArray,>)[0]

และฉันถูกสอนให้ทำที่โรงเรียนอย่างไร:

var myMax = 0
for i in 0..myArray.count {
    if (myArray[i] > myMax){myMax = myArray[i]}
}

มีวิธีที่ดีกว่าในการรับค่าสูงสุดจาก Array จำนวนเต็มใน Swift หรือไม่? ตามหลักแล้วสิ่งที่เป็นบรรทัดเดียวเช่น Ruby.max


คุณเขียนส่วนขยาย
gnasher729

ใช่บรรทัดเดียว: maxElement(myArray). ดูคำตอบที่สองในปัจจุบันคืออะไร (ของรูดอล์ฟอดัมโควิช) ด้านล่าง
leekaiinthesky

Yo เปลี่ยนที่ยอมรับคำตอบนี้
mattgabor

@mattymcgee ฉันได้อัปเดตคำตอบที่ยอมรับแล้ว
Charlie Egan

คำตอบ:


299

ได้รับ:

let numbers = [1, 2, 3, 4, 5]

Swift 3:

numbers.min() // equals 1
numbers.max() // equals 5

Swift 2:

numbers.minElement() // equals 1
numbers.maxElement() // equals 5

2
ใช้งานได้กับComparableวัตถุเท่านั้นดังนั้นNSDecimalNumberจะใช้ไม่ได้เช่นกัน
Michał Hernas

2
เป็นเพียงฉันหรือไม่มีฟังก์ชันเหล่านี้ใน Swift 2?
Liron Yahdav

@LironYahdav ตอนนี้พวกเขาเป็นวิธีการ แก้ไขแล้ว. ขอบคุณ!
Rudolf Adamkovič

2
หมายเหตุใน Swift 3 ได้เปลี่ยนชื่อเป็นเพียงmin()และmax().
jemmons

1
@Jezzamon ไม่ใน Swift 3 วิธีการminElementและmaxElementถูกเปลี่ยนชื่อเป็นminและmax. ดู: github.com/apple/swift-evolution/blob/master/proposals/…ฉันเข้าใจความสับสนของคุณเนื่องจากฟังก์ชันฟรีminและmaxยังคงมีอยู่ ดูตัวอย่างเช่นgist.github.com/lorentey/d679064cb29df4558534d619319a1d9e
jemmons

95

อัปเดต: นี่น่าจะเป็นคำตอบที่ยอมรับตั้งแต่maxElementปรากฏใน Swift


ใช้ผู้ทรงอำนาจreduce:

let nums = [1, 6, 3, 9, 4, 6];
let numMax = nums.reduce(Int.min, { max($0, $1) })

ในทำนองเดียวกัน:

let numMin = nums.reduce(Int.max, { min($0, $1) })

reduceรับค่าแรกที่เป็นค่าเริ่มต้นสำหรับตัวแปรตัวสะสมภายในจากนั้นใช้ฟังก์ชันที่ผ่าน (ในที่นี้จะไม่ระบุชื่อ) กับตัวสะสมและแต่ละองค์ประกอบของอาร์เรย์อย่างต่อเนื่องและเก็บค่าใหม่ในตัวสะสม จากนั้นค่าตัวสะสมสุดท้ายจะถูกส่งกลับ


1
สมบูรณ์แบบในสิ่งที่ฉันกำลังมองหา ดูเหมือนว่ามีหลายอย่างที่ไม่ได้อยู่ใน iBook!
Charlie Egan

2
สิ่งเหล่านี้เป็นเพียงเทคนิคการเขียนโปรแกรมที่ใช้งานได้ทั่วไปไม่ได้เฉพาะเจาะจงสำหรับ Swift
Jean-Philippe Pellet

10
@ Jean-PhilippePellet คุณสามารถทำให้สิ่งนี้ง่ายขึ้นเป็นเพียง: nums.reduce(Int.min, max)เนื่องจากmaxต้นแบบนั้นตรงกับประเภทที่reduceคาดไว้แล้ว
drewag

มีเหตุผลอะไรที่ใช้ไม่ได้กับอาร์เรย์ของคู่ผสม?
Nicholas

3
ลายเซ็นฟังก์ชันต่ำสุด / สูงสุดตรงกับลายเซ็นผสม: พารามิเตอร์เพื่อให้คุณสามารถส่งผ่านฟังก์ชันได้เอง:let numMax = nums.reduce(Int.min, combine: max)
Leslie Godwin

38

กับสวิฟท์ 5 Array, อื่น ๆ เช่นSequenceวัตถุพิธีสารสอดคล้อง ( Dictionary, Setฯลฯ ) มีสองวิธีที่เรียกว่าmax()และmax(by:)ผลตอบแทนว่าองค์ประกอบสูงสุดในลำดับหรือnilถ้าลำดับเป็นที่ว่างเปล่า


# 1 ใช้Array's max()วิธี

ถ้าชนิดองค์ประกอบภายในสอดลำดับของคุณเพื่อComparableโปรโตคอล (มันอาจจะเป็นString, Float, Characterหรือหนึ่งในชั้นเรียนของคุณเองหรือ struct) คุณจะสามารถที่จะใช้max()ที่มีดังต่อไปนี้การประกาศ :

@warn_unqualified_access func max() -> Element?

ส่งคืนองค์ประกอบสูงสุดในลำดับ

รหัส Playground ต่อไปนี้แสดงให้ใช้max():

let intMax = [12, 15, 6].max()
let stringMax = ["bike", "car", "boat"].max()

print(String(describing: intMax)) // prints: Optional(15)
print(String(describing: stringMax)) // prints: Optional("car")
class Route: Comparable, CustomStringConvertible {

    let distance: Int
    var description: String { return "Route with distance: \(distance)" }

    init(distance: Int) {
        self.distance = distance
    }

    static func ==(lhs: Route, rhs: Route) -> Bool {
        return lhs.distance == rhs.distance
    }

    static func <(lhs: Route, rhs: Route) -> Bool {
        return lhs.distance < rhs.distance
    }

}

let routes = [
    Route(distance: 20),
    Route(distance: 30),
    Route(distance: 10)
]

let maxRoute = routes.max()
print(String(describing: maxRoute)) // prints: Optional(Route with distance: 30)

# 2 ใช้Array's max(by:)วิธี

หากประเภทองค์ประกอบภายในลำดับของคุณไม่เป็นไปตามComparableโปรโตคอลคุณจะต้องใช้max(by:)ที่มีการประกาศดังต่อไปนี้:

@warn_unqualified_access func max(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Element?

ส่งคืนองค์ประกอบสูงสุดในลำดับโดยใช้เพรดิเคตที่กำหนดเป็นการเปรียบเทียบระหว่างองค์ประกอบ

รหัส Playground ต่อไปนี้แสดงให้ใช้max(by:):

let dictionary = ["Boat" : 15, "Car" : 20, "Bike" : 40]

let keyMaxElement = dictionary.max(by: { (a, b) -> Bool in
    return a.key < b.key
})

let valueMaxElement = dictionary.max(by: { (a, b) -> Bool in
    return a.value < b.value
})

print(String(describing: keyMaxElement)) // prints: Optional(("Car", 20))
print(String(describing: valueMaxElement)) // prints: Optional(("Bike", 40))
class Route: CustomStringConvertible {

    let distance: Int
    var description: String { return "Route with distance: \(distance)" }

    init(distance: Int) {
        self.distance = distance
    }

}

let routes = [
    Route(distance: 20),
    Route(distance: 30),
    Route(distance: 10)
]

let maxRoute = routes.max(by: { (a, b) -> Bool in
    return a.distance < b.distance
})

print(String(describing: maxRoute)) // prints: Optional(Route with distance: 30)

ใน Swift 3 "maxElement" ถูกเปลี่ยนชื่อเป็น "max"
Nicolai Henriksen

16

คำตอบอื่น ๆ นั้นถูกต้องทั้งหมด แต่อย่าลืมว่าคุณสามารถใช้ตัวดำเนินการรวบรวมได้ดังนี้:

var list = [1, 2, 3, 4]
var max: Int = (list as AnyObject).valueForKeyPath("@max.self") as Int

คุณยังสามารถหาค่าเฉลี่ยได้ในลักษณะเดียวกัน:

var avg: Double = (list as AnyObject).valueForKeyPath("@avg.self") as Double

ไวยากรณ์นี้อาจมีความชัดเจนน้อยกว่าโซลูชันอื่น ๆ แต่ก็น่าสนใจที่-valueForKeyPath:ยังสามารถใช้งานได้ :)


11

คุณสามารถใช้กับreduce:

let randomNumbers = [4, 7, 1, 9, 6, 5, 6, 9]
let maxNumber = randomNumbers.reduce(randomNumbers[0]) { $0 > $1 ? $0 : $1 } //result is 9

4
var numbers = [1, 2, 7, 5];    
var val = sort(numbers){$0 > $1}[0];

2
สำหรับฉันแล้วสิ่งนี้ดูเหมือนvar myMax = sort(myArray,>)[0]
Charlie Egan

3
การจัดเรียงมีค่าใช้จ่ายมากเกินไป
vy32

4

ด้วย Swift 1.2 (และอาจจะก่อนหน้านี้) คุณต้องใช้:

let nums = [1, 6, 3, 9, 4, 6];
let numMax = nums.reduce(Int.min, combine: { max($0, $1) })

สำหรับการทำงานกับค่าสองเท่าฉันใช้สิ่งนี้:

let nums = [1.3, 6.2, 3.6, 9.7, 4.9, 6.3];
let numMax = nums.reduce(-Double.infinity, combine: { max($0, $1) })

1
คุณสามารถทำได้เช่นlet numMax = nums.reduce(-Double.infinity, combine: max)กันลายเซ็นฟังก์ชันสูงสุดตรงกับลายเซ็นรวม: พารามิเตอร์
Leslie Godwin

3

ใน Swift 2.0 วิธีการminElementและmaxElementกลายเป็นSequenceTypeโปรโตคอลคุณควรเรียกสิ่งเหล่านี้ว่า:

let a = [1, 2, 3]
print(a.maxElement()) //3
print(a.minElement()) //1

ใช้maxElementเป็นฟังก์ชั่นที่ไม่เหมือนmaxElement(a)คือสามารถใช้งานได้ในขณะนี้

ไวยากรณ์ของสวิฟท์อยู่ในฟลักซ์ดังนั้นฉันสามารถยืนยันนี้ในXcode version7 beta6

อาจมีการแก้ไขในอนาคตดังนั้นฉันขอแนะนำให้คุณตรวจสอบเอกสารก่อนที่จะใช้วิธีการเหล่านี้


3

Swift 3.0

คุณสามารถลองใช้รหัสนี้โดยใช้โปรแกรม

func getSmallAndGreatestNumber() -> Void {

    let numbers = [145, 206, 116, 809, 540, 176]
    var i = 0
    var largest = numbers[0]
    var small = numbers[0]
    while i < numbers.count{

        if (numbers[i] > largest) {
            largest = numbers[i]
        }
        if (numbers[i] < small) {
            small = numbers[i]
        }
        i = i + 1
    }
    print("Maximum Number ====================\(largest)")// 809
    print("Minimum Number ====================\(small)")// 116
}


0

อัปเดตสำหรับ Swift 3/4:

ใช้บรรทัดโค้ดด้านล่างเพื่อค้นหาค่าสูงสุดจากอาร์เรย์

var num = [11, 2, 7, 5, 21]
var result = num.sorted(){
    $0 > $1
}
print("max from result: \(result[0])") // 21

-1

คุณยังสามารถจัดเรียงอาร์เรย์ของคุณแล้วใช้array.firstหรือarray.last


5
ซึ่งช้ากว่าในการคำนวณ คุณสามารถหาค่าสูงสุดของเวลาเชิงเส้นได้
Charlie Egan

ฉันเป็น @CharlieEgan ใหม่มากคุณช่วยอธิบายเวลาเชิงเส้นหรือชี้ให้ฉันดูบทแนะนำได้ไหม ขอบคุณมาก
Saad Ghadir

อ่าน 'ความซับซ้อนของเวลา' บ้าง( en.wikipedia.org/wiki/Time_complexity ) นี้ยังเป็นมูลค่าการอ่าน: bigocheatsheet.com ตัวอย่างการทำงานที่ดีที่นี่: khanacademy.org/computing/computer-science/algorithms
Charlie Egan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.