Swift 在对象数组中搜索值(映射)的更好方法

Swift 在对象数组中搜索值(映射)的更好方法,swift,Swift,我有一个名为Room的类,我在其中存储关于我家中某个特定房间的信息(房间的名称、图像等)。在我的主ViewController中,我创建了一个房间数组,并为它们指定了一些值。稍后,我想在这个房间数组中搜索名为“自习室”的房间 func findARoom(named room: String) -> Room { for i in 0..<rooms.count { if rooms[i].roomName == room {

我有一个名为Room的类,我在其中存储关于我家中某个特定房间的信息(房间的名称、图像等)。在我的主ViewController中,我创建了一个房间数组,并为它们指定了一些值。稍后,我想在这个房间数组中搜索名为“自习室”的房间

func findARoom(named room: String) -> Room {
    for i in 0..<rooms.count {
        if rooms[i].roomName == room {    
            return rooms[i]
        }
    }
}
视图控制器:

import UIKit

class MainViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, RoomCellDelegate, MQTTModelDelegate {

    var server = [MQTTModel()]
    let cellId = "cellId"
    var rooms: [Room] = [Room]()
    var roomTableView = UITableView()

    override func viewDidLoad() {
        super.viewDidLoad()
        createRoomArray()
        findARoom(named: "Study Room")

    }

    // Setting up the array of rooms
    func createRoomArray() {
        rooms.append(Room(roomName: "Living Room", roomImage: UIImage(named: "Living_Room")!, port: 48712))
        rooms.append(Room(roomName: "Study Room", roomImage: UIImage(named: "Study_Room")!, port: 1883))
        rooms.append(Room(roomName: "Bedroom", roomImage: UIImage(named: "Bedroom")!, port: 1883))    
    }        

    func findARoom(named room: String) -> Room {
        for i in 0..<rooms.count {
            if rooms[i].roomName == room {    
                return rooms[i]
            }
        }
    }
}
导入UIKit
类MainViewController:UIViewController、UITableViewDelegate、UITableViewDataSource、RoomCellDelegate、MQTTModelDelegate{
var server=[MQTTModel()]
let cellId=“cellId”
var房间:[房间]=[房间]()
var roomTableView=UITableView()
重写func viewDidLoad(){
super.viewDidLoad()
createRoomArray()
findARoom(命名为“自习室”)
}
//设置房间阵列
func createRoomArray(){
附加(房间(房间名称:“客厅”,房间图像:UIImage(名称:“客厅”)!,端口:48712))
房间。附加(房间(房间名称:“书房”,房间图像:UIImage(名称:“书房”)!,端口:1883))
房间。追加(房间(房间名称:“卧室”,房间图像:UIImage(名称:“卧室”)!,端口:1883))
}        
func findARoom(命名房间:String)->room{
对于0中的i..您可以尝试

if let res = rooms.first(where:{ $0.roomName == "Study Room" }) {

}
你可以试试

if let res = rooms.first(where:{ $0.roomName == "Study Room" }) {

}

如果你想在不在O(1)时间内迭代整个数组,就可以搜索<代码>房间,你应该考虑使用<代码>字典<代码>而不是一个数组,它类似于C++中的映射。 您的ViewController代码需要修改如下:

import UIKit

class MainViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, RoomCellDelegate, MQTTModelDelegate {

    var server = [MQTTModel()]
    let cellId = "cellId"
    var rooms: [String: Room] = [String: Room]()  // Declare the dictionary
    var roomTableView = UITableView()

    override func viewDidLoad() {
        super.viewDidLoad()
        createRoomDictionary()
        findARoom(named: "Study Room")

    }

    // Setting up the dictionary of rooms
    func createRoomDictionary() {
        rooms["Living Room"] = Room(roomName: "Living Room", roomImage: UIImage(named: "Living_Room")!, port: 48712)
        rooms["Study Room"] = Room(roomName: "Study Room", roomImage: UIImage(named: "Study_Room")!, port: 1883)
        rooms["Bedroom"] = Room(roomName: "Bedroom", roomImage: UIImage(named: "Bedroom")!, port: 1883)
    }        

    func findARoom(named room: String) -> Room {
        return rooms[room]
    }
}

如果你想在不在O(1)时间内迭代整个数组,就可以搜索<代码>房间,你应该考虑使用<代码>字典<代码>而不是一个数组,它类似于C++中的映射。 您的ViewController代码需要修改如下:

import UIKit

class MainViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, RoomCellDelegate, MQTTModelDelegate {

    var server = [MQTTModel()]
    let cellId = "cellId"
    var rooms: [String: Room] = [String: Room]()  // Declare the dictionary
    var roomTableView = UITableView()

    override func viewDidLoad() {
        super.viewDidLoad()
        createRoomDictionary()
        findARoom(named: "Study Room")

    }

    // Setting up the dictionary of rooms
    func createRoomDictionary() {
        rooms["Living Room"] = Room(roomName: "Living Room", roomImage: UIImage(named: "Living_Room")!, port: 48712)
        rooms["Study Room"] = Room(roomName: "Study Room", roomImage: UIImage(named: "Study_Room")!, port: 1883)
        rooms["Bedroom"] = Room(roomName: "Bedroom", roomImage: UIImage(named: "Bedroom")!, port: 1883)
    }        

    func findARoom(named room: String) -> Room {
        return rooms[room]
    }
}

如前所述,您可以使用,例如:

但是你说:

我希望能够以相同的方式调用
findARoom()
函数,但不能遍历整个数组

不幸的是,确实执行了一个
for
循环。只需查看该方法。它仍然是O(n),就像您自己的实现一样

如果您是说您不想为
循环编写自己的
,那么
first
(或类似)只是编写相同内容的一种更简洁的方法,但要意识到它并不比您的方法更有效

如果您真的想享受哈希性能,可以构建一个字典:

let rooms: [Room] = ...
let dictionary = Dictionary(grouping: rooms, by: { $0.roomName })
生成的
词典
是一个
[字符串:[Room]]

现在,当您在this
字典中查找房间时,您将享受哈希键性能:

if let room = dictionary["Study Room"]?.first { ... }

恕我直言,这种字典结构在这样的应用程序中是不值得的,而且
first(where:)
是一个非常好、简洁的解决方案。但是如果你真的不想让它循环并且真的需要O(1)性能,你应该知道
first
将无法实现这一点。

正如已经指出的,你可以使用,例如:

但是你说:

我希望能够以相同的方式调用
findARoom()
函数,但不能遍历整个数组

不幸的是,确实执行了一个
for
循环。只需查看该方法。它仍然是O(n),就像您自己的实现一样

如果您是说您不想为
循环编写自己的
,那么
first
(或类似)只是编写相同内容的一种更简洁的方法,但要意识到它并不比您的方法更有效

如果您真的想享受哈希性能,可以构建一个字典:

let rooms: [Room] = ...
let dictionary = Dictionary(grouping: rooms, by: { $0.roomName })
生成的
词典
是一个
[字符串:[Room]]

现在,当您在this
字典中查找房间时,您将享受哈希键性能:

if let room = dictionary["Study Room"]?.first { ... }

恕我直言,这种字典结构在这样的应用程序中是不值得的,而且
first(where:)
是一个非常好的简洁解决方案。但是如果你真的不想让它循环,并且真的需要O(1)性能,你应该知道
first
将无法实现这一点。

对于大多数事情,使用
数组。first(where:{$0.name==“stringToMatch”}
将非常快

我刚刚做了一个快速的基准测试,在我现在非常低端的原始iPad Air上运行时关闭了优化功能,有100000个结构数组,其中包含一个名称字段,
first(其中:)
在大约0.026秒内匹配了一个项目。你可能看不到那么大的延迟。(即搜索在数组中随机索引处出现的项。强制字符串与数组中的最后一个元素匹配会将
第一个(其中:)
的速度降低到0.047秒左右(≈1/20秒)

编辑: 这是我用来先计时的代码(其中:)


对于大多数情况,使用
array.first(其中:{$0.name==“stringToMatch”}
将非常快

我刚刚做了一个快速的基准测试,在我现在非常低端的原始iPad Air上运行时关闭了优化功能,有100000个结构数组,其中包含一个名称字段,
first(其中:)
在大约0.026秒内匹配了一个项目。你可能看不到那么大的延迟。(即搜索在数组中随机索引处出现的项。强制字符串与数组中的最后一个元素匹配会将
第一个(其中:)
的速度降低到0.047秒左右(≈1/20秒)

编辑: 这是我用来先计时的代码(其中:)


谢谢,字典就是我要找的。你能详细解释一下为什么你认为字典结构在这种情况下不值得吗?当数组太小以至于循环不重要时,它会占用额外的内存吗?还是其他什么?再次感谢你花时间回答。Exactl