Swift 中领域列表的时间复杂度

问题描述

我想知道 Realm Lists 是如何快速实现的。更具体地说,我想知道它们是链表还是它们的工作方式类似于数组列表。例如,在索引处检索项目的时间复杂度是多少。假设我有一个长度为 m 的领域列表 A,我想检索 A[n],这个操作会像链表一样在 O(n) 中运行,还是像在数组列表中一样在 O(k) 中运行。

编辑:

以下是对问题的更多说明:

假设我想将用户的好友列表存储在 Realm 数据库中。我这样做的方法是定义一个新的类用户,如下所示:

Class User: Object{
    @objc dynamic var name: String?
    @objc dynamic var userName: String?
    @objc dynamic var email: String?
    var friendList = RealmSwift.List<String>() //Contains the names of all friends
}

假设我已经将一些朋友添加到我用户的朋友列表中,并且在我的应用程序的其他地方我想访问这个朋友列表并显示一个特定的朋友:

var realm = try! Realm()
var user = realm.objects(User.self)[0]
var friendTodisplay = user.friendList[4]
print(friendTodisplay)

我想知道 user.friendList[4] 操作的时间复杂度是多少。如果 Realm 将 RealmSwift.List 视为一个链表,那么复杂度必须是 O(n) 而如果当用户调用到内存时,RealmSwift.List 被实现为一个 ArrayList 然后访问列表中的第四个内存地址将是 O(1)。

我的好奇心来自于想知道哪个更快:

  1. 遍历列表并找到我们想要显示的朋友的名字:
var realm = try! Realm()
var user = realm.objects(User.self)[0]
var friendName = "Peter"
for friend in user.friendList{
    if friend == friendName {
        print(friend)
    }
}

  1. 知道我们想要显示的朋友的索引,比如索引 4:
var realm = try! Realm()
var user = realm.objects(User.self)[0]
var friendTodisplay = user.friendList[4]
print(friendTodisplay)

在这两种情况下,假设朋友的名字或我们使用的索引存在于friendList列表中。

解决方法

由于涉及的变量数量和 Realm 的固有性质,该问题将无法直接回答。我会提供一些信息,但让我澄清一点很重要。

Realm 不支持列表中的原语(非常好)。

编辑: 10.7 版添加了对过滤器/查询以及基元上的聚合函数的支持,因此以下信息不再完全有效。但是,这仍然是需要注意的。

所以你不会想要这样做

var friendList = RealmSwift.List<String>()

然而,您需要定义一个 FriendClass 来保存您朋友的详细信息

class FriendClass: Object {
   @objc dynamic var friendName = ""
}

然后这样做

let friendList = List<FriendClass>()

现在回答你的问题:

您的问题是关于通过遍历列表知道索引来寻找朋友。虽然您可以以编程方式执行任一操作,但这都不是理想的解决方案。

如果你想为你的朋友 Peter 找到你的 FriendClass 对象,这是最快的方法

if let peter = realm.objects(FriendClass.self).filter("friendName == 'Peter'").first {
   //do something with the peter object
}

请记住,这适用于领域中的所有朋友对象。您同样可以在特定列表上执行相同的操作。因此,如果您的用户对象有一个friendsList 列表:

if let peter = user.friendsList.filter("friendName == 'Peter'").first {
   //do something with the peter object
}

这是可变位:Realm 对象是延迟加载的。这允许 Realm 包含数百万个对象,但在需要它们之前不会将它们加载到内存中。这样可以防止设备不堪重负。

这是一个巨大的变量,因为磁盘访问以及对象是否已经加载等都会产生影响。但是,使用我上面介绍的技术,无论是朋友列表中的一个朋友还是 10,000 个朋友,查询几乎都是即时的。

我们的一个项目有 10GB 的数据,如上所示的过滤器显示了 Realm 的即时响应。

现在是其他变量:

  1. 主键

如果您的对象有主键,您可以直接读取该对象而不会搞砸

let peter = realm.object(ofType: FriendClass.self,forPrimaryKey: "peters key")

为了清楚起见,具有主键的对象需要 O(log n) 时间。 n 是数据库中该类型对象的数量。简而言之,找回好友所需的时间与 Realm 中的对象总数无关。

  1. 索引

索引对象使写入速度稍慢,但使查询速度更快,在上面的示例中,如果 name 设置为 indexedProperty,则在查询该属性时会提高整体读取速度>

  1. 列表

列表是间接的另一层,一般来说,它比直接读取对象“慢”。话虽如此,“较慢”是高度主观的,并且与用例相关。花 0.03 秒从 100,000 个列表中检索一个朋友并没有影响。