javascriptarrayssortingarray-splice

Reorder Array based on value in an object


please is there a way to turn subject1 to subject2. if you notice, the chemistry in the subject2 occurs at interval of 3.


const subjects = [
    { "name": "Math", "score": 32 },
    { "name": "Chemistry", "score": 17 },
    { "name": "English", "score": 17 },
    { "name": "Math", "score": 55 },
    { "name": "Chemistry", "score": 21 },
    { "name": "Chemistry", "score": 75 },
    { "name": "Chemistry", "score": 45 },
    { "name": "Physics", "score": 9 },
    { "name": "Physics", "score": 4 },
    { "name": "Physics", "score": 21 },
    { "name": "Physics", "score": 11 },
    { "name": "Physics", "score": 21 },
    { "name": "Physics", "score": 11 },
    { "name": "Physics", "score": 21 },
    { "name": "Physics", "score": 11 },
    { "name": "Physics", "score": 11 },
];

const Newsubjects = [
    { "name": "Math", "score": 32 },
    { "name": "English", "score": 17 },
    { "name": "Chemistry", "score": 17 },  *********
    { "name": "Math", "score": 55 },
    { "name": "Physics", "score": 9 },
    { "name": "Chemistry", "score": 21 },  *********
    { "name": "Physics", "score": 4 },
    { "name": "Physics", "score": 21 },
    { "name": "Chemistry", "score": 75 },   *********
    { "name": "Physics", "score": 21 },
    { "name": "Physics", "score": 11 },
    { "name": "Chemistry", "score": 45 },   *********
    { "name": "Physics", "score": 21 },
    { "name": "Physics", "score": 11 },
    { "name": "Physics", "score": 21 },
    { "name": "Physics", "score": 11 },
];

SO i created this simple for loop, It works well

const subjects = [
    { "name": "Math", "score": 32 },
    { "name": "Chemistry", "score": 17 },
    { "name": "English", "score": 17 },
    { "name": "Math", "score": 55 },
    { "name": "Chemistry", "score": 21 },
    { "name": "Chemistry", "score": 75 },
    { "name": "Chemistry", "score": 45 },
    { "name": "Geo", "score": 9 },
    { "name": "Physics", "score": 4 },
    { "name": "Arab", "score": 21 },
    { "name": "Hausa", "score": 11 },
    { "name": "Yoruba", "score": 21 },
    { "name": "Commerce", "score": 11 },
    { "name": "Spanish", "score": 21 },
    { "name": "German", "score": 11 },
    { "name": "Gov", "score": 11 },
];

let filteredArray = subjects.filter(value => value.name == "Chemistry");
let filteredArray2 = subjects.filter(value => value.name != "Chemistry");
//console.log(filteredArray)
for (let i = 0; i <= filteredArray2.length; i++)
{
       if (i % 3 == 0 ) {
            filteredArray2.splice( i, 0, { "name": "Agric", "score": 11 } )
       }

}
console.log(filteredArray2)

Then whenever I try to change the value of the splice to the filteredArray, so that it won't be hardcoded { "name": "Agric", "score": 11 } I added another for loop because I wanted to add the value from the filtered array

for (let i = 0; i <= filteredArray2.length; i++)
{
    for (let j = 0; j <= filteredArray.length; j++)
    {
       if (i % 3 == 0) {
        filteredArray2.splice(i,0, filteredArray[j],)
        }
  
    }
}

Please am open to suggestions or any idea As the goal is to just rearrange the array based on the chemistry object and make it occur with the interval of 3

Thank you for your time


Solution

  • You could add some fixes to your code.

    let filteredArray = subjects.filter(value => value.name == "Chemistry");
    let filteredArray2 = subjects.filter(value => value.name != "Chemistry");
    
    
    for (let i = 0; i <= filteredArray2.length && filteredArray.length; i++){
      i % 3 === 2 && filteredArray2.splice( i++ , 0, filteredArray.shift());
    }
    
    filteredArray2.forEach(item => console.log(JSON.stringify(item)));
    <script>
    const subjects = [
        { "name": "Math", "score": 32 },
        { "name": "Chemistry", "score": 17 },
        { "name": "English", "score": 17 },
        { "name": "Math", "score": 55 },
        { "name": "Chemistry", "score": 21 },
        { "name": "Chemistry", "score": 75 },
        { "name": "Chemistry", "score": 45 },
        { "name": "Physics", "score": 9 },
        { "name": "Physics", "score": 4 },
        { "name": "Physics", "score": 21 },
        { "name": "Physics", "score": 11 },
        { "name": "Physics", "score": 21 },
        { "name": "Physics", "score": 11 },
        { "name": "Physics", "score": 21 },
        { "name": "Physics", "score": 11 },
        { "name": "Physics", "score": 11 },
    ];
    </script>

    It's possible to make the code at least twice faster with building the result array manually. Also avoid Array::shift() to mutate an array since write operations are slow.

    let filteredArray = subjects.filter(value => value.name == "Chemistry");
    let filteredArray2 = new Array(subjects.length);
    let j = 0;
    for(let i = 0, n = 0; i < subjects.length; i++){
      if(subjects[i].name === 'Chemistry'){
        continue;
      }
      if(j % 3 === 2 && n < filteredArray.length){
        filteredArray2[j++] = filteredArray[n++];
      }
      filteredArray2[j++] = subjects[i];
    }
    filteredArray2.forEach(item => console.log(JSON.stringify(item)));
    <script>
    const subjects = [
        { "name": "Math", "score": 32 },
        { "name": "Chemistry", "score": 17 },
        { "name": "English", "score": 17 },
        { "name": "Math", "score": 55 },
        { "name": "Chemistry", "score": 21 },
        { "name": "Chemistry", "score": 75 },
        { "name": "Chemistry", "score": 45 },
        { "name": "Physics", "score": 9 },
        { "name": "Physics", "score": 4 },
        { "name": "Physics", "score": 21 },
        { "name": "Physics", "score": 11 },
        { "name": "Physics", "score": 21 },
        { "name": "Physics", "score": 11 },
        { "name": "Physics", "score": 21 },
        { "name": "Physics", "score": 11 },
        { "name": "Physics", "score": 11 },
    ];
    </script>

    And a benchmark:

    enter image description here

    <script benchmark data-count="3000000">
    
        const subjects = [
            { "name": "Math", "score": 32 },
            { "name": "Chemistry", "score": 17 },
            { "name": "English", "score": 17 },
            { "name": "Math", "score": 55 },
            { "name": "Chemistry", "score": 21 },
            { "name": "Chemistry", "score": 75 },
            { "name": "Chemistry", "score": 45 },
            { "name": "Physics", "score": 9 },
            { "name": "Physics", "score": 4 },
            { "name": "Physics", "score": 21 },
            { "name": "Physics", "score": 11 },
            { "name": "Physics", "score": 21 },
            { "name": "Physics", "score": 11 },
            { "name": "Physics", "score": 21 },
            { "name": "Physics", "score": 11 },
            { "name": "Physics", "score": 11 },
        ];
    
        // @benchmark original
        {
        let filteredArray = subjects.filter(value => value.name == "Chemistry");
        let filteredArray2 = subjects.filter(value => value.name != "Chemistry");
    
    
        for (let i = 0; i <= filteredArray2.length && filteredArray.length; i++){
          i % 3 === 2 && filteredArray2.splice( i++ , 0, filteredArray.shift());
        }
        filteredArray2;
        }
    
        // @benchmark optimized
        {
        let filteredArray = subjects.filter(value => value.name == "Chemistry");
        let filteredArray2 = new Array(subjects.length);
        let j = 0;
        for(let i = 0, n = 0; i < subjects.length && n < filteredArray.length; i++){
          if(subjects[i].name === 'Chemistry'){
            continue;
          }
          if(j % 3 === 2 && n < filteredArray.length){
            filteredArray2[j++] = filteredArray[n++];
          }
          filteredArray2[j++] = subjects[i];
        }
        filteredArray2;
        }
        
        // @benchmark moonwave99
        function arrangeBySubject(subjects, subject) {
          const subjectEntries = subjects.filter((x) => x.name === subject);
          const nonSubjectEntries = subjects.filter((x) => x.name !== subject);
    
          return Array.from({ length: subjects.length }, (_, index) => {
              if (index % 3 === 2 && subjectEntries.length) {
                  return subjectEntries.shift();
              }
              return nonSubjectEntries.shift();
          });
        }
        // @run
        arrangeBySubject(subjects, 'Chemistry');
    
    
    </script>
    <script src="https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js"></script>