1

I'm trying to implement multiple sorting on nested array based on keys and sort order.

I'm able to sort an array based on the key and order

I've done the following code for sorting on array,

return array.sort((a, b) => {
      let i = 0, result = 0;
      while (i < sortBy.length && result === 0) {
        if (typeof a[sortBy[i].prop] == "string") {
          result = sortBy[i].direction * (a[sortBy[i].prop].toString() < b[sortBy[i].prop].toString() ? -1 : (a[sortBy[i].prop].toString() > b[sortBy[i].prop].toString() ? 1 : 0));
        } else {
          result = sortBy[i].direction * (a[sortBy[i].prop] < b[sortBy[i].prop] ? -1 : (a[sortBy[i].prop] > b[sortBy[i].prop] ? 1 : 0));
        }
        i++;
      }
      return result;
    });

My Input Data is given below,

array = [{ x: [{ d: 4 }, { d: 2 }, { d: 3 }, { d: 1 }], b: 'v' }, { x: [{ d: 8 }, { d: 7 }, { d: 5 }, { d: 6 }], b: 's' }];
sortBy= [{ 'prop': 'b', 'direction': 1 }, { 'prop': 'd', 'direction': 1}];

I expected an output like below,

array = [{ x: [{ d: 5 }, { d: 6 }, { d: 7 }, { d: 8 }], b: 's' },{ x: [{ d: 1 }, { d: 2 }, { d: 3 }, { d: 4 }], b: 'v' }];

But I'm getting the below result,

array = [{ x: [{ d: 8 }, { d: 7 }, { d: 5 }, { d: 6 }], b: 's' },{ x: [{ d: 4 }, { d: 2 }, { d: 3 }, { d: 1 }], b: 'v' }];

I'm stuck on how to solve this logical problem. can anyone help me on this.

7

2 Answers 2

1

You're close, what you will want to do is call your sort method on the inner arrays that have the property x. Then afterwords call it on the original array. That will sort the subarrays with the d property first, then afterword sort outer array by b.

array = [{ x: [{ d: 4 }, { d: 2 }, { d: 3 }, { d: 1 }], b: 'v' }, { x: [{ d: 8 }, { d: 7 }, { d: 5 }, { d: 6 }], b: 's' }];
sortBy= [{ 'prop': 'b', 'direction': 1 }, { 'prop': 'd', 'direction': 1}];

function sortFunc(a, b) {
  let i = 0, result = 0;
  while (i < sortBy.length && result === 0) {
    if (typeof a[sortBy[i].prop] == "string") {
      result = sortBy[i].direction * (a[sortBy[i].prop].toString() < b[sortBy[i].prop].toString() ? -1 : (a[sortBy[i].prop].toString() > b[sortBy[i].prop].toString() ? 1 : 0));
    } else {
      result = sortBy[i].direction * (a[sortBy[i].prop] < b[sortBy[i].prop] ? -1 : (a[sortBy[i].prop] > b[sortBy[i].prop] ? 1 : 0));
    }
    i++;
  }
  return result;
}

array.forEach(arr => arr.x = arr.x.sort(sortFunc));
array = array.sort(sortFunc);
console.log(array);
    

Sign up to request clarification or add additional context in comments.

Comments

1

From what I see you need to make this one recursive and call the function whenever you hit an array in your object. Take a look at this

let input = [
{ x: [{ d: 4 }, { d: 2 }, { d: 3 }, { d: 1 }], b: 'v' }, 
{ x: [{ d: 8 }, { d: 7 }, { d: 5 }, { d: 6 }], b: 's' }
];

const sortingInstructions = [
  {prop: 'b', direction: 1},
  {prop: 'd', direction: 1}
];

const isArray = Obj => {
  return typeof(Obj) === 'object' && Obj.length !== undefined
}

const nestedSort = SortingArray => {
  for(let obj of SortingArray){
  	for(let key of Object.keys(obj)){
    	if(isArray(obj[key])){
        nestedSort(obj[key])
      }
    }  	
  }
  for(let instruction of sortingInstructions){

    SortingArray.sort((a,b) => {
      if(typeof(a[instruction.prop]) === 'string'){
        return instruction.direction*b[instruction.prop].localeCompare(a[instruction.prop])
      }
      if(typeof(a[instruction.prop]) === 'number'){
        return instruction.direction*(b[instruction.prop]-a[instruction.prop]);
      }
    })
  }
	
  
  return SortingArray;
}

nestedSort(input);
console.log(input);

What this does is the following.

  1. if you hit an array in your object you call the function recursively on this array

  2. you sort the array by all your instructions (the ones further down in your instructions beeing the dominant ones as they are used to sort the latest)

  3. if what you are hitting is a string you use localeCompare to sort it

As this is recursive it will also run on any depth of object. So e.g.

let input = [
  { x: [{y:[{ d: 4 }, { d: 2 }, { d: 3 }, { d: 1 }]}], b: 'v' }, 
  { x: [{z:[{ d: 8 }, { d: 7 }, { d: 5 }, { d: 6 }]}], b: 's' }
]

would also work

Comments

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.