简体   繁体   中英

sort objects array by specific value in different keys

I have this array -

let array = [
  {
    "id": 123,
    "pair": 312
  }, 
  {
    "id": 321,
    "pair": 111
  }, 
  {
    "id": 312,
    "pair": 123
  },
  {
    "id": 111,
    "pair": 321
  }
];

And i need it to be sorted like this =

let array = [
  {
    "id": 123,
    "pair": 312
  }, 
  {
    "id": 312,
    "pair": 123
  },
  {
    "id": 321,
    "pair": 111
  }, 
  {
    "id": 111,
    "pair": 321
  }
];

Which means that i need to find the matched value of the pair key in the object, and put it right after the first element (eventually i need the to be sorted in pairs order - of course the array will be way bigger and mixed) i could not find a efficient way to achieve this.

this is what i tried - it feels very unefficient

products is the array i get from the server.

let pairs = [];
    let prods = [...products];
    for(let product of prods){
      if(product.matched){
        continue;
      }
        let pairStock = product.pairStock;
        let companyId = product.company;
        let matched = prods.filter(prod => prod.productId === pairStock && String(prod.company) === String(companyId));
        if(matched.length > 0){
          pairs.push(product);
          pairs.push(matched[0]);
          let index = prods.findIndex(prod => prod.productId === matched[0].productId);
          prods[index].matched = true;
        }
  };

this will sort data when the number of items that are linked togather is between 0 and array.length .

let products = [
  { productId: 'PK0154', pairStock: 'PK0112-02' },
  { productId: 'PK0112-02', pairStock: 'PK0154' },
  { productId: 'MGS-140', pairStock: 'MGS-136' },
  { productId: 'GM-0168', pairStock: 'GM-0169' },
  { productId: 'GM-0169', pairStock: 'GM-0168' },
  { productId: 'MGS-136', pairStock: 'MGS-140' },
]

function sort(data) {
  var mappedArray = {}
  data.forEach(obj => (mappedArray[obj.productId] = obj))
  data.sort((a, b) => a.productId.localeCompare( b.productId) )
  var addToRes = (res, id) => {
    if (id !== undefined && mappedArray[id] !== undefined) {
      var obj = mappedArray[id]
      mappedArray[id] = undefined
      res.push(obj)
      addToRes(res, obj.pairStock)
    }
  }
  var result = []
  data.forEach(item => addToRes(result, item.productId))
  return result
}

console.log(sort(products))

its results

0: {productId: "GM-0168", pairStock: "GM-0169"}
1: {productId: "GM-0169", pairStock: "GM-0168"}
2: {productId: "MGS-136", pairStock: "MGS-140"}
3: {productId: "MGS-140", pairStock: "MGS-136"}
4: {productId: "PK0112-02", pairStock: "PK0154"}
5: {productId: "PK0154", pairStock: "PK0112-02"}

The performant way (store a map of products and look up each product's pair by it's id) - O(n*2):

const productsObj = {};
products.forEach(product => productsObj[product.id] = product);

const [seenProducts, pairedProducts] = [{}, []];
products.forEach(product => {
  const productPair = productsObj[product.pair);
  if (!seenProducts[product.id]) pairedProducts.push(...[product, productPair])
  seenProducts[productPair.id] = true;
});

console.log(pairedProducts)

The intuitive way O(n^2):

// Find the next pair if a pair doesn't already exist
const arr = [];

for (let i = 0; i < products.length; i++) {
  const containsPair = arr.some(item => item.pair === products[i].id);
  if (containsPair === false) {
    const productPair = products.slice(i).find(({ id }) => id === item.pair));
    arr.push(...[products[i], productPair]);
  }
}

console.log(arr)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM