将对象映射到其自己的属性是否不好?

时间:2019-07-01 20:21:41

标签: typescript data-structures

我经常发现自己绕过具有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发生变化,则地图中的相应键不会更改,因此感觉很脆弱。

这是不好的做法吗?如果是这样,什么是实现我正在寻找的功能的更好方法?

2 个答案:

答案 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>;