Cara yang benar untuk menemukan maks dalam Array di Swift

121

Sejauh ini saya memiliki cara yang sederhana (tetapi berpotensi mahal):

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

Dan bagaimana saya diajarkan untuk melakukannya di sekolah:

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

Apakah ada cara yang lebih baik untuk mendapatkan nilai maksimum dari Array integer di Swift? Idealnya sesuatu yang satu baris seperti Ruby.max

Charlie Egan
sumber
Anda menulis ekstensi.
gnasher729
Ya, satu baris: maxElement(myArray). Lihat apa jawaban kedua (Rudolf Adamkovic) saat ini di bawah.
leekaiinthesky
Yo mengubah jawaban yang diterima untuk ini
mattgabor
@mattymcgee Saya telah memperbarui jawaban yang diterima.
Charlie Egan

Jawaban:

299

Diberikan:

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

Cepat 3:

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

Cepat 2:

numbers.minElement() // equals 1
numbers.maxElement() // equals 5
Rudolf Adamkovič
sumber
2
Bekerja hanya pada Comparableobjek, jadi NSDecimalNumbertidak akan berfungsi misalnya.
Michał Hernas
2
Apakah hanya saya atau apakah fungsi ini tidak ada di Swift 2?
Liron Yahdav
@LironYahdav Mereka sekarang metode. Tetap. Terima kasih!
Rudolf Adamkovič
2
Catatan di Swift 3 ini telah diubah namanya menjadi sederhana min()dan max().
jemmons
1
@Jezzamon No. Dalam Swift 3 metode minElementdan maxElementdiubah namanya menjadi mindan max. lihat: github.com/apple/swift-evolution/blob/master/proposals/… Saya mengerti kebingungan Anda, karena fungsinya gratis mindan maxjuga masih ada. Lihat, misalnya, gist.github.com/lorentey/d679064cb29df4558534d619319a1d9e
jemmons
95

Pembaruan: Ini mungkin jawaban yang diterima sejak maxElementmuncul di Swift.


Gunakan Yang Mahakuasa reduce:

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

Demikian pula:

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

reducemengambil nilai pertama yang merupakan nilai awal untuk variabel akumulator internal, lalu menerapkan fungsi yang diteruskan (di sini, anonim) ke akumulator dan setiap elemen array secara berturut-turut, dan menyimpan nilai baru dalam akumulator. Nilai akumulator terakhir kemudian dikembalikan.

Jean-Philippe Pellet
sumber
1
Sempurna, persis seperti yang saya cari. Sepertinya ada banyak hal yang tidak ada di iBook!
Charlie Egan
2
Itu hanya teknik pemrograman fungsional umum, tidak spesifik untuk Swift.
Jean-Philippe Pellet
10
@ Jean-PhilippePellet Anda sebenarnya dapat menyederhanakan ini menjadi: nums.reduce(Int.min, max)karena maxprototipe sudah cocok dengan tipe yang reducediharapkan
drewag
apakah ada alasan mengapa ini tidak bekerja dengan array ganda?
Nicholas
3
Tanda tangan fungsi min / maks cocok dengan tanda tangan gabungan: parameter sehingga Anda bisa meneruskan fungsi itu sendiri:let numMax = nums.reduce(Int.min, combine: max)
Leslie Godwin
38

Dengan Swift 5, Arrayseperti objek SequenceProtokol lain yang sesuai ( Dictionary,, Setdll), memiliki dua metode yang dipanggil max()dan max(by:)yang mengembalikan elemen maksimum dalam urutan atau niljika urutannya kosong.


# 1. Menggunakan Array'smax() metode

Jika jenis elemen dalam urutan sesuai untuk Comparableprotokol (mungkin itu String, Float, Characteratau salah satu dari kelas kustom atau struct), Anda akan dapat menggunakan max()yang memiliki berikut deklarasi :

@warn_unqualified_access func max() -> Element?

Mengembalikan elemen maksimum dalam urutan.

Kode Playground berikut ditampilkan untuk digunakan 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. Menggunakan Array'smax(by:) metode

Jika jenis elemen di dalam urutan Anda tidak sesuai dengan Comparableprotokol, Anda harus menggunakan max(by:)yang memiliki deklarasi berikut :

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

Mengembalikan elemen maksimum dalam urutan, menggunakan predikat yang diberikan sebagai perbandingan antar elemen.

Kode Playground berikut ditampilkan untuk digunakan 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)
Imanou Petit
sumber
Di Swift 3 "maxElement" telah diganti namanya menjadi "max"
Nicolai Henriksen
16

Jawaban lainnya semuanya benar, namun jangan lupa Anda juga bisa menggunakan operator collection, sebagai berikut:

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

Anda juga dapat menemukan rata-rata dengan cara yang sama:

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

Sintaks ini mungkin kurang jelas dibandingkan beberapa solusi lain, tetapi menarik untuk dilihat bahwa -valueForKeyPath:masih dapat digunakan :)

Sam
sumber
11

Anda dapat menggunakan dengan reduce:

let randomNumbers = [4, 7, 1, 9, 6, 5, 6, 9]
let maxNumber = randomNumbers.reduce(randomNumbers[0]) { $0 > $1 ? $0 : $1 } //result is 9
Khuong
sumber
4
var numbers = [1, 2, 7, 5];    
var val = sort(numbers){$0 > $1}[0];
androabhay
sumber
2
Bagi saya ini terlihat sepertivar myMax = sort(myArray,>)[0]
Charlie Egan
3
Pengurutan memiliki terlalu banyak overhead.
vy32
4

Dengan Swift 1.2 (dan mungkin sebelumnya) Anda sekarang perlu menggunakan:

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

Untuk bekerja dengan nilai ganda saya menggunakan sesuatu seperti ini:

let nums = [1.3, 6.2, 3.6, 9.7, 4.9, 6.3];
let numMax = nums.reduce(-Double.infinity, combine: { max($0, $1) })
Penaklukan Allen
sumber
1
Anda juga bisa melakukan ini let numMax = nums.reduce(-Double.infinity, combine: max), tanda tangan fungsi maks cocok dengan tanda tangan parameter gabungan.
Leslie Godwin
3

Di Swift 2.0, minElementdan maxElementmenjadi metode SequenceTypeprotokol, Anda harus memanggilnya seperti:

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

Menggunakan maxElementsebagai fungsi seperti maxElement(a)ini tidak tersedia sekarang.

Sintaks Swift sedang berubah, jadi saya bisa mengonfirmasi ini di Xcode versi7 beta6 .

Ini mungkin diubah di masa mendatang, jadi saya sarankan Anda lebih baik memeriksa dokumen sebelum Anda menggunakan metode ini.

Shi XiuFeng
sumber
3

Swift 3.0.0

Anda dapat mencoba kode ini secara terprogram.

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
}
Sankalap Yaduraj Singh
sumber
0

Diperbarui untuk Swift 3/4:

Gunakan di bawah baris kode sederhana untuk menemukan max dari array;

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

Anda juga dapat mengurutkan array Anda lalu menggunakan array.firstatauarray.last

Saad Ghadir
sumber
5
Ini secara komputasi lebih lambat. Anda dapat menemukan maks dalam waktu linier.
Charlie Egan
Saya @CharlieEgan yang sangat baru, dapatkah Anda menjelaskan waktu linier atau mengarahkan saya ke tutorial. Terima kasih banyak
Saad Ghadir
melakukan beberapa membaca tentang 'kompleksitas waktu' ( en.wikipedia.org/wiki/Time_complexity ). Ini juga patut dibaca: bigocheatsheet.com . Beberapa contoh yang berhasil di sini: khanacademy.org/computing/computer-science/algorithms
Charlie Egan