-3

I have a sorted array and want to rearrange it so that bigger balance property goes first and smaller the next.

var arr = [{...}, {...}, {...}];
arr = reorder(arr);

Before:

[
  {name: 'a', 'surname': 'a', balance: 10},
  {name: 'b', 'surname': 'b', balance: 21},
  {name: 'c', 'surname': 'c', balance: 43},
  {name: 'd', 'surname': 'd', balance: 47}
]

After:

[
  {name: 'd', 'surname': 'd', balance: 47},
  {name: 'c', 'surname': 'c', balance: 43},
  {name: 'b', 'surname': 'b', balance: 21},
  {name: 'a', 'surname': 'a', balance: 10}
]
ArtX
  • 3
  • 3
  • 3
    And why are you storing this in an object/dictionary with small integer keys? Wouldn't an array be a more logical structure? – Scott Sauyet Aug 30 '19 at 13:27
  • 1
    Welcome to Stack Overflow! Please take the [tour] (you get a badge!), have a look around, and read through the [help], in particular [*How do I ask a good question?*](/help/how-to-ask) I also recommend Jon Skeet's [Writing the Perfect Question](https://codeblog.jonskeet.uk/2010/08/29/writing-the-perfect-question/). Please **search** before posting. There are **lots** of questions about doing this already here on SO. More about searching [here](/help/searching). – T.J. Crowder Aug 30 '19 at 13:28
  • Your "Before" looks more like an array than a "dictionary"... – Heretic Monkey Aug 30 '19 at 13:28
  • 2
    I've linked some questions whose answers show you how to do this, but I **strongly** recommend using an array instead. Arrays are designed for ordered data. – T.J. Crowder Aug 30 '19 at 13:31
  • Use `Object.values(dict)` that returns array. You can use Array.sort see here on MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort – Riddell Aug 30 '19 at 13:35
  • My apologies, make a dict example wrong. Fixed it. Dict have other properties like name and surname, because I use dict instead of array and want to sort it with them – ArtX Aug 30 '19 at 13:36
  • 1
    The problem is not with the types of your elements (`{name: 'a', 'surname': 'a', balance: 10}`.) Those are fine as objects. But your wrapper, described by the code as an object and by you as a dictionary, is not appropriate. Much better would be an array, `[{name: 'a', balance: 10}, {name: 'b', balance: 21}, ...]`. That could be easily sorted. – Scott Sauyet Aug 30 '19 at 13:40
  • 1
    @T.J.Crowder I think this is very likely a duplicate, but it doesn't appear that the OP wants to do the "put my property names in order" thing. If the object were an array (which it almost is) it would be a simple `.sort()` invocation. – Pointy Aug 30 '19 at 13:43
  • @Pointy: agreed. This probably has come up before, but those suggested dups don't seem to match. – Scott Sauyet Aug 30 '19 at 13:44

2 Answers2

1

You can turn your object into an array (which it probably should be anyway), sort it, and then copy the properties back:

var arr = Object.assign([], dict);
arr.sort((a, b) => b.balance - a.balance);
Object.assign(dict, arr);

Or, if you'd rather create a new dict instead of mutating the old one -

const dict = {
  0: {name: 'a', 'surname': 'a', balance: 10},
  1: {name: 'b', 'surname': 'b', balance: 21},
  2: {name: 'c', 'surname': 'c', balance: 43},
  3: {name: 'd', 'surname': 'd', balance: 47}
}

const reorder = (o = {}) =>
  Object.assign(
    {},
    Object
      .assign([], o)
      .sort((a, b) => b.balance - a.balance)
  )

const result =
  reorder(dict)

console.log(result) // original dict is unchanged

Output

{
  "0": {
    "name": "d",
    "surname": "d",
    "balance": 47
  },
  "1": {
    "name": "c",
    "surname": "c",
    "balance": 43
  },
  "2": {
    "name": "b",
    "surname": "b",
    "balance": 21
  },
  "3": {
    "name": "a",
    "surname": "a",
    "balance": 10
  }
}
Mulan
  • 129,518
  • 31
  • 228
  • 259
Pointy
  • 405,095
  • 59
  • 585
  • 614
  • Slightly cross with myself: I was going to suggest this to the OP and got caught up in the `length` property. But `length` isn't an own property, so...it's not a problem. :-) – T.J. Crowder Aug 30 '19 at 13:52
  • 1
    *"Or, if you'd rather create a new dict instead of mutating the old one"* Why not just `const result = Object.assign({}, arr)` on the end of your first solution? :-) – T.J. Crowder Aug 30 '19 at 13:57
  • 2
    Thanks gang, I was expecting someone who's not cursed as I am with being unable to find a duplicate ever to do so, but this is fine :) – Pointy Aug 30 '19 at 14:08
0

I strongly recommend using an array for this. Arrays are designed for ordered access, and sorting is easily accomplished with the sort method they have.

But if you want to continue to use an object, in addition to Pointy's excellent suggestion, you can use sort without having to create extra objects, provided you want to sort dict in place:

dict.length = Object.keys(dict).length;
Array.prototype.sort.call(dict, (a, b) => b.balance - a.balance);
delete dict.length;

Live Example:

const dict = {
  0: {name: 'a', 'surname': 'a', balance: 10},
  1: {name: 'b', 'surname': 'b', balance: 21},
  2: {name: 'c', 'surname': 'c', balance: 43},
  3: {name: 'd', 'surname': 'd', balance: 47}
};
dict.length = Object.keys(dict).length;
Array.prototype.sort.call(dict, (a, b) => b.balance - a.balance);
delete dict.length;
console.log(dict);

Only delete the length if you really have to. In some cases, using delete on an object can impact the performance of subsequent property lookups (not that it usually matters).

If dict may have non-index properties or gaps, then replace

dict.length = Object.keys(dict).length;

with

dict.length = Math.max.apply(Math, Object.keys(dict).filter(key => String(+key) === key)) + 1;

Live Example:

const dict = {
  0: {name: 'a', 'surname': 'a', balance: 10},
  1: {name: 'b', 'surname': 'b', balance: 21},
  2: {name: 'c', 'surname': 'c', balance: 43},
  3: {name: 'd', 'surname': 'd', balance: 47}
};
dict.length = Math.max.apply(Math, Object.keys(dict).filter(key => String(+key) === key)) + 1;
Array.prototype.sort.call(dict, (a, b) => b.balance - a.balance);
delete dict.length;
console.log(dict);
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875