Cách chính xác để tìm giá trị tối đa trong Mảng trong Swift


121

Cho đến nay, tôi đã có một cách đơn giản (nhưng có thể tốn kém):

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

Và cách tôi được dạy để làm điều đó ở trường:

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

Có cách nào tốt hơn để nhận giá trị lớn nhất từ ​​một Mảng số nguyên trong Swift không? Lý tưởng nhất là một cái gì đó có một dòng chẳng hạn như Ruby's.max


Bạn viết một phần mở rộng.
gnasher729

Vâng, một dòng: maxElement(myArray). Xem câu trả lời thứ hai hiện tại là gì (của Rudolf Adamkovic) bên dưới.
leekaiinthesky

Thay đổi Yo rằng câu trả lời được chấp nhận để này
mattgabor

@mattymcgee Tôi đã cập nhật câu trả lời được chấp nhận.
Charlie Egan

Câu trả lời:


299

Được:

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
Chỉ hoạt động trên Comparablecác đối tượng, vì vậy, chẳng hạn như NSDecimalNumbersẽ không hoạt động.
Michał Hernas

2
Có phải chỉ tôi không hay các chức năng này không tồn tại trong Swift 2?
Liron Yahdav

@LironYahdav Chúng hiện là các phương thức. Đã sửa. Cảm ơn!
Rudolf Adamkovič

2
Lưu ý trong Swift 3, chúng đã được đổi tên thành đơn giản min()max().
jemmons

1
@Jezzamon Không. Trong Swift 3, các phương thức minElementmaxElementđược đổi tên thành minmax. xem: github.com/apple/swift-evolution/blob/master/proposal/… Tôi hiểu sự nhầm lẫn của bạn, bởi vì các chức năng miễn phí minmaxcũng vẫn tồn tại. Ví dụ: xem gist.github.com/lorentey/d679064cb29df4558534d619319a1d9e
jemmons

95

Cập nhật: Đây có lẽ nên là câu trả lời được chấp nhận kể từ khi maxElementxuất hiện trong Swift.


Sử dụng toàn năng reduce:

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

Tương tự:

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

reducenhận một giá trị đầu tiên là giá trị ban đầu cho một biến bộ tích lũy bên trong, sau đó áp dụng hàm đã truyền (ở đây là ẩn danh) cho bộ tích lũy và từng phần tử của mảng kế tiếp nhau và lưu trữ giá trị mới trong bộ tích lũy. Giá trị tích lũy cuối cùng sau đó được trả về.


1
Hoàn hảo, đúng như những gì tôi đang tìm kiếm. Có vẻ như có rất nhiều thứ không có trong iBook!
Charlie Egan

2
Đó chỉ là các kỹ thuật lập trình chức năng chung, chúng không dành riêng cho Swift.
Jean-Philippe Pellet

10
@ Jean-PhilippePellet, bạn thực sự có thể đơn giản hóa điều này thành chỉ: nums.reduce(Int.min, max)maxnguyên mẫu của nó đã phù hợp với loại reduceđang mong đợi
thu hút được

có lý do tại sao điều này không hoạt động với các mảng đôi?
Nicholas

3
Chữ ký chức năng min / max trận đấu kết hợp: chữ ký số vì vậy bạn chỉ có thể vượt qua các chức năng riêng của mình:let numMax = nums.reduce(Int.min, combine: max)
Leslie Godwin

38

Với Swift 5, Arraygiống như các Sequenceđối tượng tuân thủ Giao thức khác ( Dictionary, Setv.v.), có hai phương thức được gọi max()max(by:)trả về phần tử tối đa trong chuỗi hoặc nilnếu chuỗi trống.


# 1. Sử dụng Array's max()phương pháp

Nếu các loại nguyên tố bên trong chiếu theo trình tự của bạn để Comparablegiao thức (nó có thể String, Float, Characterhoặc một trong các lớp tùy chỉnh của bạn hoặc struct), bạn sẽ có thể sử dụng max()mà có sau tuyên bố :

@warn_unqualified_access func max() -> Element?

Trả về phần tử lớn nhất trong dãy.

Các mã Sân chơi sau sẽ hiển thị để sử dụng 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. Sử dụng Array's max(by:)phương pháp

Nếu loại phần tử bên trong chuỗi của bạn không tuân theo Comparablegiao thức, bạn sẽ phải sử dụng giao thức max(by:)khai báo sau :

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

Trả về phần tử lớn nhất trong dãy, sử dụng vị từ đã cho làm phép so sánh giữa các phần tử.

Các mã Sân chơi sau sẽ hiển thị để sử dụng 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)

Trong Swift 3 "maxElement" đã được đổi tên thành "tối đa"
Nicolai Henriksen

16

Các câu trả lời khác đều đúng, nhưng đừng quên bạn cũng có thể sử dụng toán tử tập hợp, như sau:

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

bạn cũng có thể tìm giá trị trung bình theo cách tương tự:

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

Cú pháp này có thể kém rõ ràng hơn so với một số giải pháp khác, nhưng thật thú vị khi thấy nó -valueForKeyPath:vẫn có thể được sử dụng :)


11

Bạn có thể sử dụng với 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
Đối với tôi điều này trông giống nhưvar myMax = sort(myArray,>)[0]
Charlie Egan

3
Sắp xếp có quá nhiều chi phí.
vy32

4

Với Swift 1.2 (và có thể sớm hơn), bây giờ bạn cần sử dụng:

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

Để làm việc với các giá trị Double, tôi đã sử dụng một cái gì đó như sau:

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
Bạn cũng có thể làm điều này let numMax = nums.reduce(-Double.infinity, combine: max), chữ ký hàm tối đa khớp với chữ ký tham số kết hợp:.
Leslie Godwin,

3

Trong Swift 2.0, các phương thức minElementmaxElementtrở thành SequenceTypegiao thức, bạn nên gọi chúng như:

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

Sử dụng maxElementnhư một chức năng như maxElement(a)hiện không khả dụng .

Cú pháp của Swift là dạng thay đổi, vì vậy tôi chỉ có thể xác nhận điều này trong Xcode phiên bản 7 beta6 .

Nó có thể được sửa đổi trong tương lai, vì vậy tôi khuyên bạn nên kiểm tra tài liệu trước khi sử dụng các phương pháp này.


3

Swift 3.0

Bạn có thể thử mã này theo chương trình.

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

Cập nhật cho Swift 3/4:

Sử dụng các dòng mã đơn giản dưới đây để tìm giá trị lớn nhất từ ​​mảng;

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

-1

Bạn cũng có thể sắp xếp mảng của mình và sau đó sử dụng array.firsthoặcarray.last


5
Điều này là chậm hơn về mặt tính toán. Bạn có thể tìm thấy thời gian tuyến tính tối đa.
Charlie Egan

Tôi là @CharlieEgan rất mới, bạn có thể giải thích thời gian tuyến tính hoặc chỉ cho tôi một hướng dẫn. Thanks a lot
Saad Ghadir

thực hiện một số đọc xung quanh 'độ phức tạp về thời gian' ( en.wikipedia.org/wiki/Time_complexity ). Điều này cũng đáng đọc: bigocheatsheet.com . Một số tốt làm việc ví dụ ở đây: khanacademy.org/computing/computer-science/algorithms
Charlie Egan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.