Home > Net >  Move objects from one index to a particular index in javascript
Move objects from one index to a particular index in javascript

Time:01-06

I'm new to javascript and currently using an array of object

var arrOfObj = [{name: 'eve'},{name: 'eve'},{name:'john'},
               {name:'john'}{name:'john'},{name:'mon'},{name:'mon'},
               {name:'paul'},{name:'paul'},{name:'paul'}];

what i want is to place all the objects having value 'paul' to be after value 'eve'

var arrOfObj = [{name: 'eve'},{name: 'eve'},{name:'paul'},
               {name:'paul'}{name:'paul'},{name:'mon'},{name:'mon'},
               {name:'john'},{name:'john'},{name:'john'}];

CodePudding user response:

A possible approach was to use Array.prototype.sort with a combination of a custom (the OP specific) compare function and helper compare functions where the latter solve the task of assuring an ascending sort order in the most possible generic way by also utilizing localeCompare for string type arguments.

Edit according to Teemu's comment

Note ... please OP be aware of that ...

"With a couple of ten thousands of names this will be dead slow. – Teemu "

var arrOfObj = [
  { name: 'mon' },
  { name: 'paul' },
  { name: 'john' },
  { name: 'paul' },
  { name: 'mon' },
  { name: 'eve' },
  { name: 'eve' },
  { name: 'john' },
  { name: 'paul' },
  { name: 'john' },
];
// OP ... what i want is to place all the objects
//    having value 'paul' to be after value 'eve'.

function defaultCompareAscending(a, b) {
  return ((a < b) && -1) || ((a > b) && 1) || 0;
}
function compareAscending(a, b) {
  return (a.localeCompare && b.localeCompare)
    ? a.localeCompare(b)
    : defaultCompareAscending(a, b);
}

console.log(
  "shallow copy sorted ascending by name ...",
  [...arrOfObj]
    .sort((a, b) => compareAscending(a.name, b.name))
);
console.log(
  "shallow copy sorted to the OP's conditions ...",
  [...arrOfObj]
    .sort(({ name: aName }, { name: bName}) => {

      aName = aName.toLowerCase();
      bName = bName.toLowerCase();

      return (
        (aName === 'paul' && bName === 'eve') && 1
      ) || (
        (aName === 'eve' && bName === 'paul') && -1
      ) || (
        aName === 'paul' && -1
      ) || (
        bName === 'paul' && 1
      ) || compareAscending(aName, bName);
    })
);
console.log(
  "unsorted original `arrOfObj` reference ...",
  { arrOfObj }
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

CodePudding user response:

I propose you manually handle the array without resorting to the sort function because I am not seeing any general sorting logic in your request.

What you can do is find the pauls, remove them from the array, then find the eves, and insert the removed pauls right after them.

The solution below assumes that, just like you mentioned, all objects with the same name are right next to one another and not scattered across the array.

const arrOfObj = [
    { name: 'eve' }, { name: 'eve' },
    { name:'john' }, { name:'john' }, { name:'john' },
    { name:'tom' }, { name:'tom' },
    { name:'paul' }, { name:'paul' }, { name:'paul' }
];
// get first and last indexes of paul
const firstPaulIndex = arrOfObj.findIndex(({ name }) => (name === 'paul'));
const lastPaulIndex = arrOfObj.length - 1 - arrOfObj.slice().reverse().findIndex(({ name }) => (name === 'paul'));

// remove the pauls from the array
const splicedPauls = arrOfObj.splice(firstPaulIndex, lastPaulIndex - firstPaulIndex   1);

// get the last index of eve after the removal
const lastEveIndex = arrOfObj.length - 1 - arrOfObj.slice().reverse().findIndex(({ name }) => (name === 'eve'));

// insert the pauls right after the eves
arrOfObj.splice(lastEveIndex   1, 0, ...splicedPauls);
console.log(arrOfObj);

CodePudding user response:

A parametrizable method would be like below, it also suits for large arrays.

const arrOfObj = [
  {name: 'eve'},
  {name: 'eve'},
  {name: 'john'},
  {name: 'john'},
  {name: 'john'},
  {name: 'tom'},
  {name: 'tom'},
  {name: 'paul'},
  {name: 'paul'},
  {name: 'paul'}
];

function moveAfter(source, target, array) {
  if (!array.find(({name}) => name === source)) {return array;} // Quit, no source found
  if (!array.find(({name}) => name === target)) {return array;} // Quit, no target found
  const from = array.findIndex(({name}) => name === source),
    count = array.reduce((acc, {name}, index) => name === source ? index : acc, -1) - from   1,
    values = array.splice(from, count),
    to = array.reduce((acc, {name}, index) => name === target ? index : acc, -1)   1;
  array.splice(to, 0, ...values);
  return array;
}

console.log(moveAfter('paul', 'eve', arrOfObj));

The code "moves pauls after eves in arrOfObj" in-place. And also eves after pauls, or what ever other names are passed, providing name objects are grouped by the names, and both the names are present in the array, if not, the function does nothing.

The function first searches the first index of param 1, then the last index of it, making the length for splice to cut the name objects. The position where to start to add the moved group is the last index of the param 2. The first splice then cuts the names to move from the array, and the second splice inserts the values into correct place. The complex looking reduces emulate "Array.findLastIndex` method, which currently doesn't exist in JS.

This way the array is reindexed only twice, time expensive sorting is not needed, hence the algorithm can be used with large arrays too.

You can test the code with other parameters at jsFiddle.

  •  Tags:  
  • Related