【问题标题】:Sort a Map by a property of values while keeping the keys在保留键的同时按值的属性对 Map 进行排序
【发布时间】:2018-07-26 12:11:52
【问题描述】:

我有一张声明为var cars = new Map<string, object>(); 的地图,其中string 是汽车的型号,object 包含yearprice 之类的信息。

因此,Map 将如下所示:

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

我想按price 字段(asc 或 desc)对所有整数进行排序。

我想不出任何解决方案,因为迭代 values 会丢失密钥,而像我读到的 ...cars.entries() 这样的解决方案不适用,因为值不可迭代。

附:我目前正在使用 TypeScript,但 JS 的解决方案应该仍然适用。

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

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

但是我在重建地图以保留 keys 时遇到了一些麻烦……

【问题讨论】:

标签: javascript sorting dictionary es6-map


【解决方案1】:

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; 
}));

【讨论】:

    【解决方案2】:

    地图在插入时间之后排序。这就是来龙去脉。如果您想对它进行不同的排序,您可以构建一个数组,该数组指向与地图相同的对象,但顺序不同。然后获取 Map 键,将其直接存储在对象中是有意义的。要设置数组,可以使用插入排序:

    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;
    }
    

    【讨论】:

      【解决方案3】:

      使用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;
      }
      

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

      【讨论】:

        猜你喜欢
        • 2016-07-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-20
        • 1970-01-01
        • 1970-01-01
        • 2015-06-06
        相关资源
        最近更新 更多