查找swift数组中的最大值索引

时间:2017-05-05 14:00:27

标签: arrays swift

我有2个数组。一个用于玩家,一个用于分数。 e.g。

var players = ["Bill", "Bob", "Sam", "Dave"]
var scores = [10,15,12,15]

我可以使用以下方法找到(第一个)最高分数(以及获胜者名称)的索引:

let highScore = scores.max()
let winningPlayerIndex = scores.index(of: highScore!)
let winningPlayer = players[winningPlayerIndex!]

如果只有一个得分最高的玩家但是如何为所有等于最大值的值返回多个索引(在本例中为1和3),这样可以正常工作?我需要索引然后映射回球员阵列以取出所有得分最高的球员的名字。或者有更好的方法来做所有这些吗?

6 个答案:

答案 0 :(得分:6)

您需要的是使用自定义classstructure并制作数组,然后找到最高分数,之后使用最高分数过滤您的数组。

struct Player {
    let name: String
    let score: Int
}

现在创建此播放器的数组structure

var players = [Player(name: "Bill", score: 10), Player(name: "Bob", score: 15), Player(name: "Sam", score: 12), Player(name: "Dave", score: 15)]

let maxScore = players.max(by: { $0.0.score < $0.1.score })?.score ?? 0

要获得具有max core的播放器阵列,请使用像这样的数组。

let allPlayerWithMaxScore = players.filter { $0.score == maxScore }

要获得具有高分的玩家的索引数组,请在此类阵列上使用过滤器。

let indexForPlayerWithMaxScore = players.indices.filter { players[$0].score == maxScore }
print(indexForPlayerWithMaxScore) //[1, 3]

答案 1 :(得分:2)

可接受的答案不能推广到比较元素上的计算值。获取最小/最大值和索引的最简单,最有效的方法是枚举列表并使用元组(偏移量,元素)代替:

struct Player {
    let name: String
    let stats: [Double]
}

let found = players.enumerated().max(by: { (a, b) in
   battingAvg(a.element.stats) < battingAvg(b.element.stats)
})

print(found.element.name, found.offset)  // "Joe", 42

通常,您不应该依靠相等性甚至在可能的情况下比较浮点值,如果计算成本很高,则不想重复它以在列表中找到项目。

答案 2 :(得分:1)

您可以压缩集合索引及其元素,并使用集合 min 方法获取最小值并传递谓词来比较元素。获取结果并提取元组的索引:

let numbers = [2, 4, 4, 2, 3, 1]
let minIndex = zip(numbers.indices, numbers).min(by: { $0.1 < $1.1 })?.0  // 5
let maxIndex = zip(numbers.indices, numbers).max(by: { $0.1 < $1.1 })?.0  // 1

作为元素可比的扩展:

extension Collection where Element: Comparable {
    func firstIndexOfMaxElement() -> Index? {
        zip(indices, self).max(by: { $0.1 < $1.1 })?.0
    }
    func firstIndexOfMinElement() -> Index? {
        zip(indices, self).min(by: { $0.1 < $1.1 })?.0
    }
}

用法:

numbers.firstIndexOfMinElement()  // 5


如果您需要找到最大或最小属性:

extension Collection {
    func firstIndexOfMaxElement<T: Comparable>(_ predicate: (Element) -> T) -> Index? {
        zip(indices, self).max(by: { predicate($0.1) < predicate($1.1) })?.0
    }
    func firstIndexOfMinElement<T: Comparable>(_ predicate: (Element) -> T) -> Index? {
        zip(indices, self).min(by: { predicate($0.1) < predicate($1.1) })?.0
    }
}

用法:

struct Product {
    let price: Int
}

let products: [Product] = [.init(price: 2),
                           .init(price: 4),
                           .init(price: 4),
                           .init(price: 2),
                           .init(price: 3),
                           .init(price: 1),]

let minPrice = products.firstIndexOfMinElement(\.price)    // 5

返回最大和最小元素及其索引:

extension Collection where Element: Comparable {
    func maxElementAndIndices() -> (indices: [Index], element: Element)? {
        guard let maxValue = self.max() else { return nil }
        return (indices.filter { self[$0] == maxValue }, maxValue)
    }
    func minElementAndIndices() -> (indices: [Index], element: Element)? {
        guard let minValue = self.min() else { return nil }
        return (indices.filter { self[$0] == minValue }, minValue)
    }
}

以及自定义结构/类的相应方法:

extension Collection {
    func maxElementsAndIndices<T: Comparable>(_ predicate: (Element) -> T) -> [(index: Index, element: Element)]  {
        guard let maxValue = self.max(by:{ predicate($0) < predicate($1)}) else { return [] }
        return zip(indices, self).filter { predicate(self[$0.0]) == predicate(maxValue) }
    }
    func minElementsAndIndices<T: Comparable>(_ predicate: (Element) -> T) -> [(index: Index, element: Element)] {
        guard let minValue = self.min(by:{ predicate($0) < predicate($1)}) else { return [] }
        return zip(indices, self).filter { predicate(self[$0.0]) == predicate(minValue) }
    }
}

用法:

let maxNumbers = numbers.maxElementAndIndices()  // ([1, 2], element 4)
let minNumbers =  numbers.minElementAndIndices()  // ([5], element 1)

let maxPriceIndices = products.maxElementsAndIndices(\.price)    // [(index: 1, element: Product(price: 4)), (index: 2, element: Product(price: 4))]
let minPriceIndices = products.minElementsAndIndices(\.price)    // [(index: 5, element: __lldb_expr_22.Product(price: 1))]

答案 3 :(得分:0)

有几种方法可以解决您的问题,您可以通过保存scores.max()的索引并遍历播放器列表来解决此问题,并使用then zip函数:

var max_score = scores.max()
var players_and_score = zip(players, scores)
for player in players_and_score{
    if player.1 == max_score{
       print(player.0)
    }
}

答案 4 :(得分:0)

要仅回答标题中的问题-在(单个)数组中找到最大值的索引:

extension Array where Element: Comparable {
   var indexOfMax: Index? {
      guard var maxValue = self.first else { return nil }
      var maxIndex = 0

      for (index, value) in self.enumerated() {
         if value > maxValue {
            maxValue = value
            maxIndex = index
         }
     }

     return maxIndex
   }
}

如果数组为空,扩展名将返回nil。否则,首先假设第一个值是最大值,然后遍历所有值,将索引和值更新为找到的任何较大值,最后返回结果。

答案 5 :(得分:0)

如果您有2个数组,并且需要从第一个数组中找到最大分数才能从第二个数组中提取名称,那么我建议您使用zip高阶函数将两个数组转换为一个数组并检索从那里开始的最大值。

因此,拥有您的数据将如下所示:

let players = ["Bill", "Bob", "Sam", "Dave"]
let scores = [10,15,12,15]

let data = zip(players, scores)

// max score
let maxResult = data.max(by: ({ $0.1 < $1.1 }))?.1 ?? 0
// outputs 15

// leaders
let leaders = data.filter { $0.1 >= maxResult }.map { "\($0.0) - \($0.1)" }
// outputs ["Bob - 15", "Dave - 15"]