Prawidłowy sposób na znalezienie maksimum w tablicy w języku Swift

121

Do tej pory mam prosty (ale potencjalnie drogi) sposób:

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

I jak mnie tego uczono w szkole:

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

Czy istnieje lepszy sposób na uzyskanie maksymalnej wartości z tablicy całkowitej w języku Swift? Idealnie coś, co jest jedną linią, na przykład Ruby.max

Charlie Egan
źródło
Piszesz rozszerzenie.
gnasher729
Tak, jedna linia: maxElement(myArray). Zobacz poniżej, jaka jest obecnie druga odpowiedź (Rudolf Adamkovic).
leekaiinthesky
Yo zmiana, która zaakceptowała odpowiedź na to
mattgabor
@mattymcgee Zaktualizowałem zaakceptowaną odpowiedź.
Charlie Egan

Odpowiedzi:

300

Dany:

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
Rudolf Adamkovič
źródło
2
Działa tylko na Comparableobiektach, więc NSDecimalNumberna przykład nie będzie działać.
Michał Hernas
2
Czy to tylko ja, czy te funkcje nie istnieją w Swift 2?
Liron Yahdav
@LironYahdav Teraz są metodami. Naprawiony. Dzięki!
Rudolf Adamkovič
2
Uwaga w Swift 3 zostały one przemianowane na simple min()i max().
jemmons,
1
@Jezzamon Nie. W Swift 3 metody minElementi maxElementzostały przemianowane na mini max. zobacz: github.com/apple/swift-evolution/blob/master/propeals/… Rozumiem twoje zamieszanie, ponieważ darmowe funkcje mini maxnadal istnieją. Zobacz na przykład gist.github.com/lorentey/d679064cb29df4558534d619319a1d9e
jemmons
95

Aktualizacja: To powinna być przyjętym prawdopodobnie odpowiedź ponieważ maxElementpojawił się Swift.


Użyj wszechmocnego reduce:

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

Podobnie:

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

reducepobiera pierwszą wartość, która jest wartością początkową wewnętrznej zmiennej akumulatora, następnie stosuje przekazaną funkcję (w tym przypadku jest anonimowa) do akumulatora i każdego elementu tablicy po kolei i przechowuje nową wartość w akumulatorze. Następnie zwracana jest ostatnia wartość akumulatora.

Jean-Philippe Pellet
źródło
1
Idealnie, właśnie to, czego szukałem. Wygląda na to, że jest wiele rzeczy, których nie ma w iBooku!
Charlie Egan
2
To tylko ogólne techniki programowania funkcjonalnego, które nie są specyficzne dla języka Swift.
Jean-Philippe Pellet
10
@ Jean-PhilippePellet, możesz tak naprawdę uprościć to, aby po prostu: nums.reduce(Int.min, max)ponieważ maxprototyp jest już zgodny z reduceoczekiwanym
typem
czy istnieje powód, dla którego to nie działa z tablicami podwójnych?
Nicholas
3
Sygnatury funkcji min / max są zgodne z połączeniem: sygnatura parametru, więc możesz po prostu przekazać samą funkcję:let numMax = nums.reduce(Int.min, combine: max)
Leslie Godwin
38

Szybkimi 5, Arraypodobnie jak inne Sequenceprotokołem w odpowiadające sobie przedmiotów ( Dictionary, Setitp), składa się z dwóch metod zwanych max()i max(by:)ten powrót maksymalna elementów w sekwencji lub niljeśli sekwencja jest pusta.


# 1. Używając Array'smax() metody

Jeżeli typ elementu wewnątrz firmy Przylega do sekwencji Comparableprotokołu (może to być String, Float, Characterlub jeden z niestandardowej klasy lub struktury), będzie w stanie wykorzystać max(), że ma następującą deklarację :

@warn_unqualified_access func max() -> Element?

Zwraca maksymalny element w sekwencji.

Poniższe kody Playground pokazują do użycia 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. Używając Array'smax(by:) metody

Jeśli typ elementu w twojej sekwencji nie jest zgodny z Comparableprotokołem, będziesz musiał użyć max(by:)tego, który ma następującą deklarację :

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

Zwraca maksymalny element w sekwencji, używając podanego predykatu jako porównania między elementami.

Poniższe kody Playground pokazują do użycia 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
źródło
W Swift 3 nazwa „maxElement” została zmieniona na „max”
Nicolai Henriksen
16

Pozostałe odpowiedzi są poprawne, ale nie zapominaj, że możesz również użyć operatorów kolekcji w następujący sposób:

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

możesz też znaleźć średnią w ten sam sposób:

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

Ta składnia może być mniej jasna niż niektóre inne rozwiązania, ale interesujące jest to, że -valueForKeyPath:nadal można jej używać :)

Sam
źródło
11

Możesz używać z 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
źródło
4
var numbers = [1, 2, 7, 5];    
var val = sort(numbers){$0 > $1}[0];
androabhay
źródło
2
Dla mnie wygląda to bardzo podobnievar myMax = sort(myArray,>)[0]
Charlie Egan
3
Sort ma za dużo narzutów.
vy32
4

Ze Swift 1.2 (a może wcześniej) musisz teraz użyć:

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

Do pracy z wartościami Double użyłem czegoś takiego:

let nums = [1.3, 6.2, 3.6, 9.7, 4.9, 6.3];
let numMax = nums.reduce(-Double.infinity, combine: { max($0, $1) })
Allen Conquest
źródło
1
Możesz również po prostu to zrobić let numMax = nums.reduce(-Double.infinity, combine: max), maksymalna sygnatura funkcji pasuje do sygnatury connect: parameter.
Leslie Godwin
3

W Swift 2.0 metody protokołu minElementi maxElementstają się metodami SequenceTypeprotokołu, należy je nazywać:

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

Używanie maxElementjako takiej funkcji maxElement(a)jest niedostępne teraz .

Składnia języka Swift jest zmienna , więc mogę to potwierdzić w Xcode w wersji 7 beta6 .

Może zostać zmodyfikowany w przyszłości, więc sugeruję, abyś lepiej sprawdził dokument przed użyciem tych metod.

Shi XiuFeng
źródło
3

Swift 3.0

Możesz wypróbować ten kod programowo.

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
źródło
0

Zaktualizowano dla Swift 3/4:

Użyj poniższych prostych linii kodu, aby znaleźć maksimum z tablicy;

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

Możesz również posortować tablicę, a następnie użyć array.firstlubarray.last

Saad Ghadir
źródło
5
Jest to wolniejsze obliczeniowo. Możesz znaleźć maksimum w czasie liniowym.
Charlie Egan
Jestem nowym @CharlieEgan, czy możesz wyjaśnić czas liniowy lub wskazać mi tutorial. Wielkie dzięki
Saad Ghadir
poczytaj o „złożoności czasowej” ( en.wikipedia.org/wiki/Time_complexity ). Warto też przeczytać: bigocheatsheet.com . Kilka dobrych przykładów tutaj: khanacademy.org/computing/computer-science/algorithms
Charlie Egan