Mads
Mads

Reputation: 35

Sort map based on object property while keeping key

I have created a map that contains a list of products, and the shop closest by that is selling that product, like so:

var products = new Map()
products.set('product_key', {
  shop: 'shop_key',
  distance: 1.2
})

Now what I would like to do is sort the entire map on the distance property, so that I can list the products by proximity to my location.

I use a map because I also need to go in and be able to find the distance to one specific product using the key.

Upvotes: 2

Views: 227

Answers (3)

Maxim Egorushkin
Maxim Egorushkin

Reputation: 136276

One way is to have an array of keys sorted by distance:

"use strict";

var products = new Map()
products.set('product_key', {
    shop: 'shop_key',
    distance: 1.2
})
products.set('product2_key', {
    shop: 'shop2_key',
    distance: 0.1
})
console.log(products);

var keysByDistance = Array.from(products.keys()).sort((a, b) => products.get(a).distance - products.get(b).distance);
console.log(keysByDistance.map(key => products.get(key)));

Outputs:

Map {
  'product_key' => { shop: 'shop_key', distance: 1.2 },
  'product2_key' => { shop: 'shop2_key', distance: 0.1 } }
[ { shop: 'shop2_key', distance: 0.1 },
  { shop: 'shop_key', distance: 1.2 } ]

Upvotes: 1

T.J. Crowder
T.J. Crowder

Reputation: 1074425

Map loops through its entries in insertion order; you can't sort a map, you can only create one in the sorted order you want.

For what you're doing, I'd probably use an array of entries, and then a map mapping strings to the entries that are in the array:

const productList = [
    {distance: 1.8, product_key: "one", shop: "shop_key1"},
    {distance: 1.2, product_key: "two", shop: "shop_key2"},
    {distance: 1.4, product_key: "three", shop: "shop_key3"}
];
productList.sort((a, b) => a.distance - b.distance);
const map = new Map();
productList.forEach(entry => {
    map.set(entry.product_key, entry);
});

console.log("List:");
productList.forEach(entry => {
    console.log(JSON.stringify(entry));
});
console.log("Product 'two':", map.get("two"));

That allows you to re-sort as necessary.

But again, Map iterates in insertion order, so you can do it with just a Map as the endpoint, by inserting the entries in order:

const productList = [
    {distance: 1.8, product_key: "one", shop: "shop_key1"},
    {distance: 1.2, product_key: "two", shop: "shop_key2"},
    {distance: 1.4, product_key: "three", shop: "shop_key3"}
];
productList.sort((a, b) => a.distance - b.distance);
const map = new Map();
productList.forEach(entry => {
    map.set(entry.product_key, entry);
});
productList = null; // don't need it anymore

console.log("List:");
for (let entry of map) {
    console.log(JSON.stringify(entry));
}
console.log("Product 'two':", map.get("two"));

Upvotes: 1

Jay
Jay

Reputation: 2686

Move some pieces to an array, the product key and distance, then sort that array. Do the lookup after you sort.

var products = {
   p1:300, p2:60, p3:200, p4:1000,
   p5:400, p6:600
}
var sortable = [];
for (var x in products)
  sortable.push([x, product[x]])
sortable.sort(
   function(a, b) {
      return a[1] - b[1]
   }
)

//Do lookup on the map based on first elements in sorted array

Upvotes: 0

Related Questions