按照值的属性对Map进行排序,同时保留键

4

我有一个被声明为var cars = new Map<string, object>();的地图,其中string是汽车的型号,object包含了年份和价格等信息。

因此,这个Map看起来会像这样:

Map = [
        'BMW' => {
            id: 123,
            price: 2000,
            models: {...}
        },
        'Opel' => {
            id: 1234,
            price: 3500,
            models: {...}
        },
        ....
    ]

我希望能按照价格字段(升序或降序)对所有条目进行排序。

我无法找到任何解决方案,因为迭代values会丢失键,而像...cars.entries()这样的解决方案并不适用,因为这些值不可迭代。

P.S. 我目前正在使用TypeScript,但JS的解决方案同样适用。

编辑:我尝试将地图转换为数组,如下所示:

const values = Array.from(this.cars.values());
values.sort((a, b) => {
    return (a.price < b.price) ? -1 : 1;
});

但是我在重构Map以保留keys时遇到了一些问题...


1
不,实际上并不是这样的,因为那只是对对象进行排序。我的问题是在重构 Map 时如何保留每个值的原始键。 - LostCoder
3个回答

4

Map对象会按照插入顺序迭代和保留其元素。所以,您只能创建新的Map对象。我认为最简单的方法是将旧的映射转换为数组,排序它,并转换为新的映射对象。就像这样:

let newMap = new Map([...map].sort(([k, v], [k2, v2])=> {
  if (v.price > v2.price) {
    return 1;
  }
  if (v.price < v2.price) {
    return -1;
  }
  return 0; 
}));

0

地图在插入时进行排序。这就是它的工作原理。如果您想以不同的方式进行排序,可以构建一个指向地图相同对象的数组,但具有不同的顺序。然后,为了获取地图键,将其存储在对象中是有意义的。要设置数组,可以使用插入排序:

const sorted: object[] = [];

for(const [key, car] of cars){
  car.name = key;
  const insertAt = sorted.findIndex(other => other.price < car.price) + 1;
  sorted.splice(insertAt, 0, car);
}

或者你可以之后排序(更短但更慢):

const sorted = [...cars.entries()].map(([name, car]) => ({name, ...car})).sort((a, b) => a.price - b.price);

请注意,如果您只是回退到本机类型,则使用TypeScript毫无意义。相反,您可以实现一个汽车接口,例如:
interface ICar {
  price: number;
  models: IModel[];
  id: number;
  name: string;
}

0

借鉴了AntonJonas的思路,我得到了这个解决方案。虽然不完美,但似乎可以工作。

private sortCars(cars): Map<string, iCar> {

    // Convert the map to array first and sort it by "price"
    const carList = Array.from(cars)
        .map(([brand, car]) => ({brand, ...car}))
        .sort((a, b) => {
            if (a.price === b.price) {
                return 0;
            } else {
                return a.price < b.price ? -1 : 1;
            }
        }
    );

    // Rebuild the map after sorting it.
    const carsMap = new Map();
    carList.forEach((car) => carsMap.set(car.name, car));

    return carsMap;
}

我选择将品牌名称添加到汽车对象中,以便重新构建最终的Map。相反,我也可以在原始Map中搜索对象并返回键。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接