Swift dizisinde max bulmanın doğru yolu


121

Şimdiye kadar basit (ama potansiyel olarak pahalı) bir yol buldum:

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

Ve bunu okulda nasıl yapmam öğretildi:

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

Swift'de bir tamsayı Dizisinden maksimum değeri almanın daha iyi bir yolu var mı? İdeal olarak, Ruby'ninki gibi tek satırlık bir şey.max


Bir uzantı yazarsınız.
gnasher729

Evet, bir satır: maxElement(myArray). Aşağıdaki ikinci cevabın (Rudolf Adamkovic'in) ne olduğuna bakın.
leekaiinthesky

O Yo değişim için kabul edilen cevabı bu
mattgabor

@mattymcgee Kabul edilen cevabı güncelledim.
Charlie Egan

Yanıtlar:


299

Verilen:

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
Yalnızca Comparablenesneler üzerinde çalışır , bu nedenle NSDecimalNumberörneğin çalışmaz.
Michał Hernas

2
Sadece ben miyim yoksa bu işlevler Swift 2'de yok mu?
Liron Yahdav

@LironYahdav Artık metotlar. Sabit. Teşekkürler!
Rudolf Adamkovič

2
Swift 3'te bunların basitçe min()ve olarak yeniden adlandırıldığını unutmayın max().
jemmons

1
@Jezzamon No. Swift 3 yöntem minElementve maxElementyeniden adlandırıldı edildi minve max. bkz: github.com/apple/swift-evolution/blob/master/proposals/… Karışıklıklarınızı anlıyorum, çünkü ücretsiz işlevler minve maxhala var. Örneğin, gist.github.com/lorentey/d679064cb29df4558534d619319a1d9e
jemmons

95

Güncelleme: Bu , Swift'de maxElementyayınlandığından beri muhtemelen kabul edilen cevap olmalıdır .


Yüce Olanı Kullanın reduce:

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

Benzer şekilde:

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

reducedahili bir akümülatör değişkeni için başlangıç ​​değeri olan bir ilk değeri alır, sonra aktarılan işlevi (burada anonimdir) toplayıcıya ve dizinin her bir öğesine art arda uygular ve yeni değeri toplayıcıda saklar. Son biriktirici değeri daha sonra döndürülür.


1
Mükemmel, tam aradığım şey. Görünüşe göre iBook'ta olmayan çok şey var!
Charlie Egan

2
Bunlar sadece genel işlevsel programlama teknikleridir, Swift'e özgü değildir.
Jean-Philippe Pellet

10
Jean-PhilippePellet @ aslında sadece bu kolaylaştırabilirsiniz: nums.reduce(Int.min, max)beri max'ın prototip zaten türü ile eşleşen reducebekliyor
drewag

bunun çift dizilerle çalışmamasının bir nedeni var mı?
Nicholas

3
Min / maks fonksiyon imzaları, birleştirme: parametre imzası ile eşleşir, böylece fonksiyonun kendisini geçebilirsiniz:let numMax = nums.reduce(Int.min, combine: max)
Leslie Godwin

38

Swift 5 ile, Array, gibi başka Sequenceiletişim kuralına uygun nesne ( Dictionary, Setvs.), iki adlı yöntemleri max()ve max(by:)sekansında bu dönüş maksimum element ya da nilsıra boş ise.


# 1. Kullanma Arraybireyin max()yöntemi

İçin sekans uygun olup içindeki eleman tipi ise Comparableprotokol (o olabilir String, Float, Characterveya özel sınıf veya yapı biri), kullanmak mümkün olacak max()o aşağıdaki sahiptir beyanı :

@warn_unqualified_access func max() -> Element?

Sıradaki maksimum öğeyi döndürür.

Aşağıdaki Oyun Alanı kodlarının kullanımı gösterilir 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. Kullanma Arraybireyin max(by:)yöntemi

Sıranızdaki öğe türü Comparableprotokole uymuyorsa max(by:), aşağıdaki beyana sahip olanı kullanmanız gerekecektir :

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

Verilen yüklemi öğeler arasında karşılaştırma olarak kullanarak dizideki maksimum öğeyi döndürür.

Aşağıdaki Oyun Alanı kodlarının kullanımı gösterilir 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'te "maxElement" "max" olarak yeniden adlandırıldı
Nicolai Henriksen

16

Diğer cevapların hepsi doğrudur, ancak aşağıdaki gibi koleksiyon operatörlerini de kullanabileceğinizi unutmayın:

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

ortalamayı da aynı şekilde bulabilirsiniz:

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

Bu sözdizimi diğer çözümlerden bazılarına göre daha az açık olabilir, ancak bunun -valueForKeyPath:hala kullanılabileceğini görmek ilginç :)


11

Şunları kullanabilirsiniz 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
Bana çok benziyorvar myMax = sort(myArray,>)[0]
Charlie Egan

3
Sıralama çok fazla ek yüke sahip.
vy32

4

Swift 1.2 (ve belki daha öncesi) ile artık şunları kullanmanız gerekiyor:

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

Çift değerlerle çalışmak için şöyle bir şey kullandım:

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
Bunu da yapabilirsiniz let numMax = nums.reduce(-Double.infinity, combine: max), max fonksiyon imzası comb: parametre imzasıyla eşleşir.
Leslie Godwin

3

Swift 2.0'da, minElementve protokolün maxElementmetotları haline SequenceTypegelince, onları şöyle çağırmalısınız:

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

maxElementGibi bir işlev olarak kullanmak artık maxElement(a)mümkün değil .

Swift'in sözdizimi akış halinde, bu yüzden bunu Xcode sürüm 7 beta6'da doğrulayabilirim .

Gelecekte değiştirilebilir, bu yüzden bu yöntemleri kullanmadan önce dokümanı kontrol etmenizi öneririm.


3

Swift 3.0

Bu kodu programlı olarak deneyebilirsiniz.

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 için güncellendi:

Diziden maksimum değeri bulmak için aşağıdaki basit kod satırlarını kullanın;

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

-1

Ayrıca dizinizi sıralayabilir ve ardından array.firstveyaarray.last


5
Bu hesaplama açısından daha yavaştır. Maksimumu doğrusal zamanda bulabilirsiniz.
Charlie Egan

Ben çok yeniyim @CharlieEgan, doğrusal zamanı açıklayabilir veya beni bir eğitime yönlendirebilir misin? Çok teşekkürler
Saad Ghadir

'zaman karmaşıklığı' ( en.wikipedia.org/wiki/Time_complexity ) hakkında biraz okuma yapın . Bu da okumaya değer: bigocheatsheet.com . Bazı iyi örnekleri burada çalıştı: khanacademy.org/computing/computer-science/algorithms
Charlie Egan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.