1

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;
        }
  };
5
  • it is not possible by using Array#sort. you need a grouping. btw, what have you tried? Commented Jun 15, 2020 at 18:29
  • Please show any attempts you've made to solve this yourself, regardless of efficiency. Commented Jun 15, 2020 at 18:32
  • 1
    @NinaScholz check it now Commented Jun 15, 2020 at 18:34
  • use lodash to sort like stackoverflow.com/a/45555950/3256489 Commented Jun 15, 2020 at 22:57
  • @4givN I need a way to filter on two keys. not one Commented Jun 15, 2020 at 22:59

2 Answers 2

1

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"}
Sign up to request clarification or add additional context in comments.

8 Comments

That's actually a different situation then mine because in my case there can only be pairs, i mean that there can only be a match between two items, if - arr[0].productId === arr[1].pairStock , this means that the arr[0[.pairStock === arr[1].productId
this algorithm still works and it sorts pairs ascending. output will be {id: 111, pair: 321},{id: 321, pair: 111},{id: 123, pair: 312},{id: 312, pair: 123}
I tried it on 4 products and the function returned 8 products
could you please share the input data
my bad, it's just did not work - input was - [ { 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' } ]
|
0

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)

1 Comment

I actually tried both of your methods - and they did not work

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.