【问题标题】:Finding an Element within an Array efficiently [Swift]有效地在数组中查找元素 [Swift]
【发布时间】:2022-01-13 14:19:03
【问题描述】:

目前使用以下方法在数组中查找匹配项,但我想知道是否有更有效的方法来进行此类检查。

for player in team.roster {
     if id == player.id {
          return player.name
     }
}

基本上取一个给定的变量,一个球员 id,并循环遍历球队名单以找到一个匹配的 id,这给定球队的规模是可以的,但如果对更大的数据进行类似的检查设置什么是处理此问题的更好方法?

【问题讨论】:

  • 使用默认属性team.roster.first{where: .....
  • 如果条目按它们的 id 排序,那么您可以进行二进制搜索。或者你可以维护一个索引。否则,您将始终必须遍历数组才能找到匹配的条目。使用first(where:) 并不能提高效率。
  • 为了澄清,通过“维护索引”,Martin 正在谈论构建一个将 ID 映射到玩家的字典。您需要支付一些前期费用,但随后的重复查找会变得更快。

标签: swift


【解决方案1】:

使用默认属性first{ condition }

    let id = 4
    
    let roster: [TeamMember] = [.init(id: 1, name: "Abishek", age: 19),
                               .init(id: 2, name: "Dinesh", age: 22),
                               .init(id: 3, name: "Praveen", age: 24),
                               .init(id: 4, name: "Sam", age: 25),
                               .init(id: 5, name: "David", age: 21)]
let firstMember = roster.first{$0.id == id}

print(firstMember)
print(firstMember?.name)

输出

Optional(TeamMember(id: 4, name: "Sam", age: 25.0))
Optional("Sam")

【讨论】:

  • 这更整洁,但在性能方面相当。
【解决方案2】:

@Shabnam Siddiqui 的答案是 Swifty,我大部分时间都会使用它,但二进制搜索也值得了解。

O(n) 复杂度中的 Swift 方法 first(where:) https://developer.apple.com/documentation/swift/array/1848165-first,而二分查找的最坏情况性能为 O(log n),最佳情况性能为 O(1)。

所以假设:

struct Player {
var id : Int
var name : String
}

为:

var players : [Player] = [
    Player(id: 0, name: "Bob"),
    Player(id: 1, name: "Edd"),
    Player(id: 2, name: "Jo"),
    Player(id: 3, name: "John")
]

递归解法:

func getPlayername(_ id : Int,  _ players : [Player]) -> String?{
    guard players.count > 0 else {
     print("No players found with id \(id)")
     return nil
    }
    if players.first!.id == id {
        return players.first?.name
    }else{
        return getPlayername(id, Array(players.dropFirst()))
    }
}
print(getPlayername(3, players))

解决方案二进制:

func getPlayerBinary(_ id : Int,  _ players : [Player]) -> String?{
    var startIndex = 0
    var max = players.count

    while startIndex < max {
      let midIndex = startIndex + (max - startIndex) / 2
        if players[midIndex].id == id {
            return players[midIndex].name
        } else if players[midIndex].id < id {
        lowerBound = midIndex + 1
      } else {
        max = midIndex
      }
    }
    print("No players found with id \(id)")
    return nil
}

https://www.geeksforgeeks.org/binary-search/

【讨论】:

  • 这不是二分搜索。
  • 对对对,现在编辑二进制选项:)
  • 如果你打算花时间实现二分搜索,我会选择至少让它通用,这样它就有更多的重用价值
  • 这里的各种实现:stackoverflow.com/q/31904396/1187415.
【解决方案3】:
let name = team.roster.first(where: { $0["player_id"] == id}).map{ $0["player_name"] }

【讨论】:

  • 为什么这样更高效?
  • 我确实想到了这一点,但不确定这如何像@MartinR 要求的那样更有效率。这会不会做同样的事情,只是用更少的代码行?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-04-30
  • 2014-09-07
  • 2010-10-13
  • 1970-01-01
  • 2011-03-03
  • 2017-04-10
相关资源
最近更新 更多