skip to Main Content

There are like these datas

const persons = [
  {
    label: "jhon",
    value: 1
  },
  {
    label: "Mary",
    value: 2
  },
  {
    label: "Michelle",
    value: 3
  },
  {
    label: "David",
    value: 4
  },
  {
    label: "Kerry",
    value: 5
  },
  {
    label: "Tom",
    value: 6
  }
];
const testPassedPersons = [3, 5, 6];

What do I want to do?

I need to move these persons who includes testPassedPersons number to head of array.
So now Michelle / Kerry / Tom should move, value in order from smallest to largest [3,5,6]

▼ What I need to get

const SortedPersons = [
  {
    label: "Michelle",
    value: 3
  },
  {
    label: "Kerry",
    value: 5
  },
  {
    label: "Tom",
    value: 6
  }
  {
    label: "jhon",
    value: 1
  },
  {
    label: "Mary",
    value: 2
  },
  {
    label: "David",
    value: 4
  },
];

What I’ve tried so far

actually I have a solution, but I would like to know alternative better way (specially shorter or faster)

▼ This is my way

const sortedPersons = [
  ...persons.filter((person) => testPassedPersons.includes(person.value)),
  ...persons.filter((person) => !testPassedPersons.includes(person.value))
];

▼ codesandbox url.
https://codesandbox.io/s/pensive-david-1giqnk?file=/src/index.js

5

Answers


  1. This is what I got:

    let sortedPersons = new Set();
    testPassedPersons.forEach((passedPerson) => {
      persons.forEach((person) => {
        if (passedPerson === person.value) {
          sortedPersons.add(person);
        }
      });
    });
    
    persons.forEach((person) => sortedPersons.add(person));
    sortedPersons = [...sortedPersons];
    
    console.log(sortedPersons);
    

    As code shows, I am creating a set because set will hold only unique values. We add the persons with the values in testPassedPersons, then add the rest of the persons. Since set holds unique items, the duplication won’t occur.Then, at the end, we just turn that set into an array.

    Login or Signup to reply.
  2. you can write a custom sort function.
    indexOf returns -1 if element is not found in the array.
    So if aIndex is not -1 and bIndex is -1 it means both not found. therefore keep original order of a and b.
    If aIndex is -1 only we return 1 means a should come after b.
    If bIndex is -1 only we return -1 means a should come before b (b after a). So basically what is not found in testPassedPersons comes after.
    Finally indexA - indexB will decide which comes first based on the sign.

    const persons = [  {    label: "jhon",    value: 1  },  {    label: "Mary",    value: 2  },  {    label: "Michelle",    value: 3  },  {    label: "David",    value: 4  },  {    label: "Kerry",    value: 5  },  {    label: "Tom",    value: 6  }];
    
    const testPassedPersons = [3, 5, 6];
    
    const res = [...persons].sort((a,b) => {
      const indexA = testPassedPersons.indexOf(a.value)
      const indexB = testPassedPersons.indexOf(b.value)
      if (indexA === -1 && indexB === -1) return 0;
      if (indexA === -1) return 1
      if (indexB === -1) return -1
      return indexA - indexB
      //or ternary operator
      //return (indexA === -1 && indexB === -1) ? 0 : (indexA === -1) ? 1 : (indexB === -1) ? -1 : indexA - indexB
    
    })
    
    console.log(res)
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    the implementation with 2 filters will give Mary,Michelle,Kerry,Tom for [3, 5, 6, 2] instead Michelle,Kerry,Tom,Mary. If that is the desired result you can achieve it in 1 loop instead of 2 filters(2 loops) using reduce. Also converting the passed person array to a set can help achieve O(1) lookup

    const persons = [  {    label: "jhon",    value: 1  },  {    label: "Mary",    value: 2  },  {    label: "Michelle",    value: 3  },  {    label: "David",    value: 4  },  {    label: "Kerry",    value: 5  },  {    label: "Tom",    value: 6  }];
    
    const testPassedPersons = [3, 5, 6, 2];
    const testPassedPersonsSet = new Set(testPassedPersons)
    
    const {passed,notPassed} = persons.reduce((acc,{label,value}) => {
      acc[testPassedPersonsSet.has(value) ? 'passed' : 'notPassed'].push({label,value})
      return acc
    },{passed:[],notPassed:[]})
    
    console.log([...passed,...notPassed])
    .as-console-wrapper { max-height: 100% !important; top: 0; }
    Login or Signup to reply.
  3. You could build an object with the wanted order and sort by value or move the items to bottom.

    This approach allows to move any unknown item/value either to top (value smaller than zero), bottom (a large value, like Number.MAX_VALUE) or just inbetween the given order.

    const
        persons = [{ label: "jhon", value: 1 }, { label: "Mary", value: 2 }, { label: "Michelle", value: 3 }, { label: "David", value: 4 }, { label: "Kerry", value: 5 }, { label: "Tom", value: 6 }],
        testPassedPersons = [3, 5, 6],
        order = Object.fromEntries(testPassedPersons.map((v, i) => [v, i + 1]));
    
    persons.sort((a, b) => (order[a.value] || Number.MAX_VALUE) - (order[b.value] || Number.MAX_VALUE));
    
    console.log(persons);
    .as-console-wrapper { max-height: 100% !important; top: 0; }
    Login or Signup to reply.
  4. I don’t think there’s anything really wrong with your current approach. You could save yourself a loop over the array with a partition function rather than a filter function.

    The idea with the partition function is to push the matching results into the first array (equivalent to the filter results) and then push all the others into a second array, so you have two arrays, one of matching and one of not matching results.

    A number of JS libraries have partition functions e.g. Lodash and Ramda.

    const persons = [{ label: "jhon", value: 1 }, { label: "Mary", value: 2 }, { label: "Michelle", value: 3 }, { label: "David", value: 4 }, { label: "Kerry", value: 5 }, { label: "Tom", value: 6 }];
    
    const testPassedPersons = [3, 5, 6];
    
    const partition = (data, partition_function) =>
      data.reduce(
        (acc, val) => (acc[+!partition_function(val)].push(val), acc),
        [[], []]
      );
    
    const get_sorted_persons = persons =>
      partition(persons, (person) => testPassedPersons.includes(person.value)).flat();
    
    console.log(get_sorted_persons(persons));
    Login or Signup to reply.
  5. You can simply achieve this with the help of Array.splice() method along with Array.unshift() method.

    Live Demo :

    const persons = [
      {
        label: "jhon",
        value: 1
      },
      {
        label: "Mary",
        value: 2
      },
      {
        label: "Michelle",
        value: 3
      },
      {
        label: "David",
        value: 4
      },
      {
        label: "Kerry",
        value: 5
      },
      {
        label: "Tom",
        value: 6
      }
    ];
    
    const testPassedPersons = [3, 5, 6];
    
    persons.forEach((obj, index) => {
        if (testPassedPersons.includes(obj.value)) {
        persons.splice(index, 1);
        persons.unshift(obj);
      }
    });
    
    console.log(persons)
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search