Emili Bellot Pulido
Emili Bellot Pulido

Reputation: 107

Algorithm to sort Map and reasign new order on value change

I am developing an E-Commerce using Javascript. In the section of the products of the page, I want to implement the functionality to change the order of the products setting the number in the corresponding input. You can see an image to get an idea of the interface.

Image

The algorithm I looking for has to reorder all the products if the user changes the input of the Orden column.

For example:

  1. The user sets the input Orden of the product 0003-0020 to 11 and clicks on the Guardar button.
  2. Then, the algorithm has to change the position of this product and put it second on the list. Updating its orden input value to 20.
  3. The algorithm has to update all the following products, increasing their positions +10.

If the user sets a value that already exists, the product will place below the product that already has the position entered. The position values are always multiple of 10.

The data is structured in an ArrayList that contains the product reference and its position: Its name is lista_variantes.

0: {numero: "0003-0007", posicion: 10}
1: {numero: "0003-0006", posicion: 20}
2: {numero: "0003-0004", posicion: 30}
3: {numero: "0003-0008", posicion: 40}
4: {numero: "0003-0014", posicion: 50}
5: {numero: "0003-0016", posicion: 60}
6: {numero: "0003-0017", posicion: 70}
7: {numero: "0003-0018", posicion: 80}

And then using this map, I update the Database and read the product information in the correct order. I have implemented correctly this, I only want the algorithm to achieve the example behaviour.

Upvotes: 1

Views: 443

Answers (1)

adiga
adiga

Reputation: 35243

  • You could map the array of objects and add a new property called isUpdated which checks if the posicion is same based on the index.
  • Then, sort the array based on posicion. If 2 items have the same posicion, then sort them based on isUpdated property
  • Then map the array again to remove the isUpdated property and get the posicion values based on their index

const map = [
    { numero: "0003-0007", posicion: 10 },
    { numero: "0003-0006", posicion: 20 },
    { numero: "0003-0004", posicion: 30 },
    { numero: "0003-0008", posicion: 25 }, //-- updated
    { numero: "0003-0014", posicion: 20 }, //-- updated
    { numero: "0003-0016", posicion: 60 }
]

const output = map.map((o, i) => ({ ...o, isUpdated: (i+1) * 10 !== o.posicion }))
                  .sort((a,b) => a.posicion - b.posicion || a.isUpdated - b.isUpdated)
                  .map(({ isUpdated, ...rest }, i) => ({ ...rest, posicion: (i+1) * 10 }))

console.log(output)

It would be better if you have another property to keep the posicion value before update or an onchange event which updates the isUpdated proeprty. If you have that, you can skip the step where you check whether the object has been updated or not.

Here's a snippet using for loop and some comments

const map = [
    { numero: "0003-0007", posicion: 10 },
    { numero: "0003-0006", posicion: 20 },
    { numero: "0003-0004", posicion: 30 },
    { numero: "0003-0008", posicion: 25 }, //-- updated
    { numero: "0003-0014", posicion: 20 }, //-- updated
    { numero: "0003-0016", posicion: 60 }
]

// add isUpdated property and set it to true if posicion is not equal to (i+1) * 10
for (let i = 0; i < map.length; i++) {
  const o = map[i];
  o.isUpdated = (i+1) * 10 !== o.posicion
}

// sort based on posicion
// if both have the same posicion, the subtraction returns 0
// so, || will check the next condition
// Sorting based on boolean: https://stackoverflow.com/a/54826593
map.sort((a,b) => a.posicion - b.posicion || a.isUpdated - b.isUpdated);

// delete the isUpdated property
// update the posicion based on the new index
for (let i = 0; i < map.length; i++) {
  const o = map[i];
  o.posicion = (i+1) * 10;
  delete o.isUpdated
}

console.log(map)

Upvotes: 2

Related Questions