JavaScript:从对象id到该对象的反向映射
我有一个类JavaScript:从对象id到该对象的反向映射,javascript,oop,Javascript,Oop,我有一个类Rectangle,它有一个名为id的属性,指示Rectangle 类矩形{ 建造师(描述){ this.desc=desc this.id=Symbol() } } 稍后,我需要将id放到其他一些数据结构中,我需要一种使用id 要实现这一点,我需要手动创建地图,例如 const r1=新矩形(“第一个”) 常数r2=新矩形('秒') 常数r3=新矩形('第三个') 常数映射={ [r1.id]:r1, [r2.id]:r2, [r3.id]:r3, } 因此,如果需要,我可以获取
Rectangle
,它有一个名为id
的属性,指示Rectangle
类矩形{
建造师(描述){
this.desc=desc
this.id=Symbol()
}
}
稍后,我需要将id
放到其他一些数据结构中,我需要一种使用id
要实现这一点,我需要手动创建地图,例如
const r1=新矩形(“第一个”)
常数r2=新矩形('秒')
常数r3=新矩形('第三个')
常数映射={
[r1.id]:r1,
[r2.id]:r2,
[r3.id]:r3,
}
因此,如果需要,我可以获取r1
的引用
map[r1.id]
我想知道是否有一种编程方法可以实现这种反向映射,其中id
是键,Rectangle
实例是值
此外,如果有人能为地图提供更好的名称,我将不胜感激。目前,地图的名称map
并不具有真正的描述性
最后,我想知道我们是否可以去掉
id
,只使用矩形
实例的引用?我知道答案可能是“视情况而定”,但我认为大多数情况下,对于实例或对象,我们需要一个id
。我想知道在什么情况下仅使用引用是否不会减少它?如果您愿意将外部库集成到项目中,一种可能性是使用Lodash的keyBy
方法。它将一个对象数组作为第一个输入,并使用一个函数来计算结果对象的关键点
如果我以您为例,这将是生成的代码:
import { keyBy } from 'lodash';
const r1 = new Rectangle('first');
const r2 = new Rectangle('second');
const r3 = new Rectangle('third');
const map = keyBy([r1, r2, r3], (rectangle) => rectangle.id);
您仍然需要构建阵列本身,但无论如何都必须这样做。如果您想要一个更复杂的数据结构,您可以创建一个具有数据的内部数组表示形式的类,以及一些访问它的方法。类似这样的东西(我使用的是typescript,javascript与之类似,但没有键入,而且我没有测试这是否仅适用于复制和粘贴,可能需要一些小的调整):
从'lodash'导入{keyBy,filter};
类矩形映射{
私有重新排列:矩形[];
构造函数(){
this.recArray=[];
}
addRectangle(r:矩形):无效{
这个。重新排列。推(r);
}
角度(r:矩形):无效{
this.recArray=过滤器(this.recArray,(rec)=>rec.id!==r.id);
}
getMap(key:string='id'):记录{
返回keyBy(this.recArray,rec=>rec[key]);
}
}
const myRecMap=new RectangleMap();
addRectangle(新矩形('first'));
addRectangle(新矩形('second'));
addRectangle(新矩形('third'));
log(myRecMap.getMap());
一般来说,我总是建议将Lodash用于此类数组/对象操作。它们具有很好的实用功能
我想知道是否有一个程序化的方法来实现这一逆转
映射,其中id是键,矩形实例是值
如果您需要的数据结构是一个以id
为键的映射,那么如果没有显式的键值插入,就没有现成的方法来实现这一点。您可能有两种选择:
- 对创建地图的方式有一点改进:
根据您的情况,您应该决定是将class Rectangle { constructor(desc) {...} getAsMapEntry() { return [this.id, this] } } const map = new Map([ r1.getAsMapEntry(), r2.getAsMapEntry(), r3.getAsMapEntry() ]);
方法保留在类getAsMapEntry
中,还是作为实用方法。为了简单起见,我展示了第一种方法,但我可能会选择第二种。此外,我强烈建议您在这里使用Rectangle
class,这对很多人来说都是非常有用的Map
- 您可以创建一个新的数据结构,该结构接受
s(或者更好地说,接受具有Rectangle
属性的所有类型的对象),并且内部有一个映射。这个新类就像一个适配器,使您需要的操作至少更具可读性。不要扩展id
类,因为此继承将破坏该类,因为您必须彻底更改Map
方法的先决条件。更简单的方法是通过组合进行:set
class EntityContainer { // accept an array of Rectangle (or objects having the id property) constructor(entities) { this._internalMap = new Map(entities.map(e => [e.id, e])); } _assertIsEntity(entity) { if (!entity.id) throw "not an entity" } insertOrUpdate(entity) { this._assertIsEntity(entity); this._internalMap.set(entity.id, entity); } deleteByEntity(entity) { this._assertIsEntity(entity); this.deleteById(entity.id); } deleteById(id) { this._internalMap.delete(id) } getById(id) { this._internalMap.get(id); } }
id
的逻辑隐藏在EntityContainer
类中,这意味着您可以插入实体,而不是id实体对。当然,如果您需要,也可以使用deleteByEntity
进行删除。您也可以验证实体,并且通常可以对所做的操作进行更多的控制,但需要维护一个新类。当您编写的方法只是投影\u internalMap
方法时,缺点就出现了,请参见getById
。这不是很漂亮,但在我看来可以接受,如果你必须这样做,只有几个方法
另外,如果有人能给我的名字起个更好的名字,我将不胜感激
地图-现在名称地图不是真正的描述性
当然,这是你必须决定的事情,取决于它的目的
最后,我想知道我们是否可以去掉id,只使用
矩形实例?我知道答案可能是“视情况而定”,但是
我认为大多数情况下,我们需要一个实例或应用程序的id
物体。我想知道在什么情况下只使用引用是否是正确的
你不打算剪掉它吗
同样,您没有向我们提供足够的信息,就是否更适合使用引用或
id
属性向您提供建议(只是为了说明,没有规则,一如既往)。根据您的评论“它是一个更大系统的一部分,id
可能是一个很好的折衷方案,因为它更容易在多个组件之间创建关系,尤其是当涉及到外部数据存储时。我认为最好在Rec中创建两个静态属性
class EntityContainer {
// accept an array of Rectangle (or objects having the id property)
constructor(entities) {
this._internalMap = new Map(entities.map(e => [e.id, e]));
}
_assertIsEntity(entity) {
if (!entity.id)
throw "not an entity"
}
insertOrUpdate(entity) {
this._assertIsEntity(entity);
this._internalMap.set(entity.id, entity);
}
deleteByEntity(entity) {
this._assertIsEntity(entity);
this.deleteById(entity.id);
}
deleteById(id) {
this._internalMap.delete(id)
}
getById(id) {
this._internalMap.get(id);
}
}
const r1 = new Rectangle('first')
const r2 = new Rectangle('second')
const r3 = new Rectangle('third')
const input = [r1, r2, r3];
const map = input.reduce((output, rect) => ({...output, [rect.id]: rect}), {})
console.log(map)
const r1 = new Rectangle('first')
const r2 = new Rectangle('second')
const r3 = new Rectangle('third')
const rectangles = [r1, r2, r3];
const map = rectangles.reduce((output, rectangle) => ({...output, [rectangle.id]: rectangle}), {})
console.log(map)