Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/dart/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Typescript 将对象映射到其自己的属性是一种不好的做法吗?_Typescript_Data Structures - Fatal编程技术网

Typescript 将对象映射到其自己的属性是一种不好的做法吗?

Typescript 将对象映射到其自己的属性是一种不好的做法吗?,typescript,data-structures,Typescript,Data Structures,我经常发现自己传递的对象具有标识它们的ID或名称,但也是对象的属性。例如: 类型ExampleItemName=string; 接口示例项{ 名称:ExampleItemName; 值:数字; } 我还经常需要创建这些项目的列表,我发现通过它们的名称访问这些项目很方便。我看到的最符合逻辑的数据结构是映射,即: 类型ExampleItemList=Map; 这很方便,因为我可以通过映射通过其名称访问任何项目。get,但我也可以使用for…of轻松地遍历整个列表 但是,我觉得这是错误的,因为名称

我经常发现自己传递的对象具有标识它们的ID或名称,但也是对象的属性。例如:

类型ExampleItemName=string;
接口示例项{
名称:ExampleItemName;
值:数字;
}
我还经常需要创建这些项目的列表,我发现通过它们的
名称
访问这些项目很方便。我看到的最符合逻辑的数据结构是
映射
,即:

类型ExampleItemList=Map;
这很方便,因为我可以通过
映射通过其
名称访问任何项目。get
,但我也可以使用
for…of
轻松地遍历整个列表

但是,我觉得这是错误的,因为
名称
信息是重复的-它同时存在于映射的键和值中。如果
ExampleItem
名称
发生变化,则地图中相应的键不会发生变化,因此感觉很脆弱


这种做法不好吗?如果是这样的话,有什么更好的方法来实现我想要的功能?

这本身并不是一个糟糕的做法,但有一些条件需要满足,或者您会遇到一些问题,比如您提到的问题,以及您通过更改键入的值。这种模式通常被称为键入数据的行为。最好的做法是按您知道不会更改的值(如ID)为数据设置关键帧。由于字典通常可以降低昂贵的查找函数的成本,因此在许多情况下它们是必需的,但正如我提到的和您指出的,您必须使用不会更改且唯一的值对其进行键控,或者每次使用字典时都需要更新和处理重复项。需要哪种解决方案取决于您的情况


此外,像lodash这样的库具有内置函数(您可以自己轻松编写),这些函数接收数据并为您设置键。您还将发现这些想法在其他语言中广泛使用,即使它们的名称不同(python:dictionary、Java:hashMap等)。

如果不太麻烦,您可以尝试创建自己的列表结构,以满足您的用例,例如下面的一个

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>;
类名称映射{
私有项:Set=new Set();
Add(value:V){this.items.Add(value);}
获取(键:K){
for(设e of this.items.values())如果(e.name==key)返回e;
返回未定义;
}
[Symbol.iterator](){返回此.items[Symbol.iterator]();};
}
类型ExampleItemList=NameMap;

感谢您富有洞察力的回复。我正在使用lodash,但我对它非常陌生。你能给我指出这样一个函数吗?@Ian
keyBy
函数是lodash提供给对象设置关键帧的函数名。它接受lodash可定义的任何对象(数组、对象等),并返回一个字典,其中键是您在第二个参数中指定的属性。例如:
.keyBy(collectionOfItems,keyOfPropertyToUseAsId)
我可以做到这一点,但是这个实现并不比仅仅使用一个项目数组和
数组快。查找
或类似的方法来定位一个特定的项目。因为
Get
需要遍历所有元素,所以它的O(n)时间复杂度比从哈希映射中提取元素的时间复杂度慢得多。@Ian如果必须使用
map
,那么我想您可以创建一个
map
的包装类,仍然使用
ExampleItem.name
作为键,但请确保名称只能通过包装类提供的后门方法更改。不过,如果这些项目可以是多个地图的一部分,事情可能会变得更加复杂。