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

121

У меня пока есть простой (но потенциально дорогой) способ:

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

И как меня этому учили в школе:

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

Есть ли лучший способ получить максимальное значение из целочисленного массива в Swift? В идеале что-то из одной строчки, например, Ruby's.max

Чарли Иган
источник
Вы пишете расширение.
gnasher729 04
Да, одна линия: maxElement(myArray). Посмотрите, какой в ​​настоящее время второй ответ (Рудольфа Адамковича) ниже.
leekaiinthesky
Йо, измените принятый ответ на этот вопрос
Мэттгэбор,
@mattymcgee Я обновил принятый ответ.
Чарли Иган

Ответы:

300

Дано:

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 03 фев.15,
2
Это только у меня или этих функций нет в Swift 2?
Лирон Яхдав
@LironYahdav Теперь это методы. Исправлена. Спасибо!
Рудольф Адамкович
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 много чего нет!
Чарли Иган
2
Это просто общие методы функционального программирования, они не относятся к Swift.
Jean-Philippe Pellet
10
@ Jean-PhilippePellet, вы можете упростить это до просто: nums.reduce(Int.min, max)поскольку maxпрототип уже соответствует reduceожидаемому
типу
есть ли причина, по которой это не работает с массивами двойников?
Николас
3
Сигнатуры функции min / max соответствуют сигнатуре параметра comb:, поэтому вы можете просто передать саму функцию:let numMax = nums.reduce(Int.min, combine: max)
Лесли Годвин
38

С Swift 5 Array, как и другим Sequenceпротоколом , соответствующими объекты ( Dictionary, Set, и т.д.), имеет два метода , называемые max()и max(by:)что возвращение максимального элемент в последовательности или , nilесли последовательность пуста.


# 1. Использование Array«S 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«S 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
Khuong
источник
4
var numbers = [1, 2, 7, 5];    
var val = sort(numbers){$0 > $1}[0];
androabhay
источник
2
Для меня это выглядит какvar myMax = sort(myArray,>)[0]
Чарли Иган
3
У сортировки слишком много накладных расходов.
vy32
4

В Swift 1.2 (и, возможно, ранее) вам теперь нужно использовать:

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

Для работы со значениями Double я использовал что-то вроде этого:

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), максимальная сигнатура функции соответствует сигнатуре comb: parameter.
Лесли Годвин
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, не могли бы вы объяснить линейное время или указать мне на учебник. Большое спасибо
Саад Гадир
почитайте «временную сложность» ( en.wikipedia.org/wiki/Time_complexity ). Это тоже стоит прочитать: bigocheatsheet.com . Вот несколько хороших примеров работы: khanacademy.org/computing/computer-science/algorithms
Чарли Иган