0

I have an array of objects where I need to change the order of the keys. e.g.

let data = [
  {
    "Summer": "green",
    "Winter": "white",
    "Spring": "yellow",
    "Autumn": "orange",
    "Total": 0,
    "Number": 0,
    "Difference": 0
  },
  {
    "Summer": "green",
    "Winter": "white",
    "Spring": "yellow",
    "Autumn": "orange",
    "Total": 0,
    "Number": 0,
    "Difference": 0
  },
]

what I want to achieve is:

let updated = [
  {
    "Total": 0,
    "Number": 0,
    "Summer": "green",
    "Spring": "yellow",
    "Autumn": "orange",
    "Winter": "white",
    "Difference": 0
  },
  {
    "Total": 0,
    "Number": 0,
    "Summer": "green",
    "Spring": "yellow",
    "Autumn": "orange",
    "Winter": "white",
    "Difference": 0
  }
]

I have tried cloning into a new array with the order I want and also object.assign which doesn't give me the expected result.

let newArr = [];
for (let i in data) {
  newArr.push(
    data[i].Total,
    data[i].Number,
    data[i].Summer,
    data[i].Spring,
    data[i].Autumn,
    data[i].Winter,
    data[i].Difference
  )
}

does not work as exptected and also

const objectOrder = {
  'Total': null,
  'Number': null,
  'Summer': null,
  'Spring': null,
  'Autumn': null,
  'Winter': null,
  'Difference': null,
}
for (let i of data) {
  const addObjectResource = Object.assign(objectOrder, data[i]);
  newArr.push(addObjectResource)
}
pilchard
  • 12,414
  • 5
  • 11
  • 23
jhin
  • 13
  • 1
  • 2
    Order of keys in objects is not guaranteed and it doesn't matter. Why would you like to do that? – Konrad Oct 24 '22 at 22:10
  • 2
    It is now well ordered, but it doesn't matter. [Does JavaScript guarantee object property order?](https://stackoverflow.com/questions/5525795/does-javascript-guarantee-object-property-order) (yes, but not necessarily insertion order). Use a [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map), which maintains insertion order, or array if you require a specific order of elements. – pilchard Oct 24 '22 at 22:13
  • 1
    Also your second snippet will work ([jsfiddle](https://jsfiddle.net/v4c8qrzu/1/)) but you need to clone `objectOrder` before assigning to it, otherwise you are just rewriting the same object every time. `const addObjectResource = Object.assign({...objectOrder}, data[i]);`. But [don't use `for...in` on arrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in#array_iteration_and_for...in) rather use [`for...of`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of). [jsfiddle](https://jsfiddle.net/ejfL53zt/) – pilchard Oct 24 '22 at 22:39
  • @Konrad Linkowski the reason is that I am using a 3rd party library to export objects to Excel file and the order of columns are determined by the order of the keys. – jhin Oct 25 '22 at 02:01
  • @jhin sounds like a case for nested array – Konrad Oct 25 '22 at 06:08

1 Answers1

1

Let's start by using:

  • Object.entries()
  • Array.sort()
  • Object.fromEntries()

let data = [{
    "Summer": "green",
    "Winter": "white",
    "Spring": "yellow",
    "Autumn": "orange",
    "Total": 0,
    "Number": 0,
    "Difference": 0
  },
  {
    "Summer": "green",
    "Winter": "white",
    "Spring": "yellow",
    "Autumn": "orange",
    "Total": 0,
    "Number": 0,
    "Difference": 0
  },
]

const order = ["Total", "Number", "Summer", "Spring", "Autumn", "Winter", "Difference"];
let answer1 = data.map( e => Object.fromEntries(
    Object.entries(e)
    .sort((a, b) => order.indexOf(a[0]) - order.indexOf(b[0]))
) );
console.log(answer1);

The destructuring answer posted by @pilchard looks interesting and is much more efficient than the answer I posted:

let data = [{
    "Summer": "green",
    "Winter": "white",
    "Spring": "yellow",
    "Autumn": "orange",
    "Total": 0,
    "Number": 0,
    "Difference": 0
  },
  {
    "Summer": "green",
    "Winter": "white",
    "Spring": "yellow",
    "Autumn": "orange",
    "Total": 0,
    "Number": 0,
    "Difference": 0
  },
]

let answer2 = data.map( ({ Total, Number, Summer, Spring, Autumn, Winter, Difference, })
                     => ({ Total, Number, Summer, Spring, Autumn, Winter, Difference, })); 
console.log(answer2);
Stephen Quan
  • 21,481
  • 4
  • 88
  • 75
  • 3
    probably vastly faster to just destructure and rebuild in a map, but the point is one shouldn't rely on object property order. `const result = data.map(({ Total, Number, Summer, Spring, Autumn, Winter, Difference, }) => ({ Total, Number, Summer, Spring, Autumn, Winter, Difference, }));` (you'll note the destructuring is in the same order as the returned object, *because the order is not important*) – pilchard Oct 24 '22 at 22:16
  • destructure did the trick. Thank you all. – jhin Oct 25 '22 at 02:02
  • @jhin whilst we did find and answer to your problem. Overall, it is not recommended to rely on the order of keys in an object. Is such order is important, then, you should supply that information. Similar to the `const order` array I had in answer1. Then, whenever you need the order, you use the array to drive your loop, UI, or whatever. Whenever you merely need to look up values, you use the object like a dictionary. – Stephen Quan Oct 25 '22 at 02:06