我经常发现自己绕过具有ID或名称的对象,这些ID或名称可以标识它们,但它们也是该对象的属性。例如:
type ExampleItemName = string;
interface ExampleItem {
name: ExampleItemName ;
value: number;
}
我还经常需要创建这些项目的列表,我发现能够通过它们的name
访问这些项目很方便。为此,我看到的最逻辑的数据结构是Map
,即:
type ExampleItemList = Map<ExampleItemName, ExampleItem>;
这既方便又方便,因为我可以使用name
访问Map.get
中的任何项目,但是我也可以使用for...of
轻松地遍历整个列表。
但是,这对我来说是错的,因为name
信息是重复的-它同时存在于键和映射的值中。如果name
中的ExampleItem
发生变化,则地图中的相应键不会更改,因此感觉很脆弱。
这是不好的做法吗?如果是这样,什么是实现我正在寻找的功能的更好方法?
答案 0 :(得分:1)
这本身不是一个坏习惯,但是有一些条件需要满足,否则您会遇到诸如您提到的通过更改其键值来提及的问题。这种模式通常称为密钥数据操作。最佳做法是使用您不会更改的值(例如ID)来对数据进行键控。由于字典通常可以减少昂贵的查找功能的成本,因此在许多情况下它们是必需的,但是正如我提到的那样,您必须指出,您必须使用不会改变且唯一的值来键控它们,或者需要更新和处理每次您使用字典时都会重复。需要哪种解决方案取决于您的情况。
此外,像lodash这样的库具有内置的函数(您可以轻松编写自己),这些函数可以接收数据并为您键入数据。您还会发现这些想法在其他语言中也被广泛使用,即使它们使用不同的名称(python:字典,Java:hashMap等)
答案 1 :(得分:0)
如果不是很不方便,您可以尝试创建自己的满足您的用例的列表结构,例如以下示例。
class NameMap<K, V extends { name: K }> {
private items: Set<V> = new Set();
Add(value: V) { this.items.add(value); }
Get(key: K) {
for(let e of this.items.values()) if(e.name == key) return e;
return undefined;
}
[Symbol.iterator]() { return this.items[Symbol.iterator](); };
}
type ExampleItemList = NameMap<ExampleItemName, ExampleItem>;