Правильний спосіб знайти макс в масиві в Swift


121

Я поки що мав простий (але потенційно дорогий) спосіб:

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

І як мене вчили робити це в школі:

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

Чи є кращий спосіб отримати максимальне значення з цілого масиву в Swift? В ідеалі щось, що є однією лінією, як Рубі.max


Ви пишете розширення.
gnasher729

Так, одна лінія: maxElement(myArray). Дивіться, яка зараз друга відповідь (Рудольф Адамкович) нижче.
leekaiinthesky

Йо змінив, що прийняв відповідь на це
маттгабор

@mattymcgee Я оновив прийняту відповідь.
Чарлі Еган

Відповіді:


299

Подано:

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

Швидкий 3:

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

Швидкий 2:

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

2
Працює лише над Comparableоб’єктами, тому NSDecimalNumberне працюватиме, наприклад.
Michał Hernas

2
Це тільки я або ці функції відсутні в Swift 2?
Лірон Ягдав,

@LironYahdav Вони тепер методи. Виправлено. Дякую!
Рудольф Адамкович

2
Зауважте, що в Swift 3 вони були перейменовані на просто min()і max().
jemmons

1
@Jezzamon No. У 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, здається!
Чарлі Еган

2
Це просто загальні функціональні методи програмування, вони не характерні для Swift.
Жан-Філіп Пеллет

10
@ Jean-PhilippePellet ви можете насправді спростити це до всього лише: nums.reduce(Int.min, max)оскільки maxпрототип вже відповідає типу, який reduceочікується
drewag

є причина, чому це не працює з масивами парних?
Микола

3
Підписи функції min / max відповідають підпису параметрів комбінування: параметр, так що ви можете просто передати саму функцію:let numMax = nums.reduce(Int.min, combine: max)
Леслі Годвін

38

З Swift 5, Arrayяк і з іншими Sequenceоб'єктами, що відповідають протоколу ( Dictionary, Setі т. Д.), Є два методи, які називаються, max()і max(by:)які повертають максимальний елемент у послідовності або nilякщо послідовність порожня.


№1. Використання Arrayросійського max()методу

Якщо тип елемента всередині вашої послідовності Відповідності норм по Comparableпротоколу (це може бути String, Float, Characterабо один з призначеного для користувача класу або структури), ви будете мати можливість використовувати , max()що має наступне заяву :

@warn_unqualified_access func max() -> Element?

Повертає максимальний елемент у послідовності.

Показані для використання наступні коди ігрових майданчиків 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російського max(by:)методу

Якщо тип елемента у вашій послідовності не відповідає Comparableпротоколу, вам доведеться використовувати таке, max(by:)що має таке оголошення :

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

Повертає максимальний елемент у послідовності, використовуючи даний предикат як порівняння між елементами.

Показані для використання наступні коди ігрових майданчиків 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"
Ніколай Генріксен

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

З 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), підпис максимальної функції відповідає підпису параметру комбінування: параметр.
Леслі Годвін

3

В Swift 2.0, minElementі maxElementстають методи SequenceTypeпротоколу, ви повинні назвати їх , як:

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

Використання maxElementтакої функції, як maxElement(a)зараз, недоступне .

Синтаксис Swift знаходиться в потоці, тому я можу просто підтвердити це в 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
Це обчислювально повільніше. Ви можете знайти максимум в лінійний час.
Чарлі Еган

Я зовсім новий @CharlieEgan, чи можете ви пояснити лінійний час або вказати мені на підручник. Велике спасибі
Saad Ghadir

зробити читання навколо "складності часу" ( en.wikipedia.org/wiki/Time_complexity ). Про це також варто прочитати: bigocheatsheet.com . Деякі хороші приклади роботи тут: khanacademy.org/computing/computer-science/algorithms
Чарлі Еган
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.