0

I have this kind of data:

{
 "Item 1": {
    "Purchased": {
      "quantity": "5.000",
      "cost": "80.000"
    },
    "Rent": {
      "quantity": "45.000",
      "cost": "25200.000"
    }
  },
  "Item 2": {
    "Purchased": {
      "quantity": "35.000",
      "cost": "25000.000"
    },
    "Rent": {
      "quantity": "0.0",
      "cost": "0.0"
    }
  },
  "Item 3": {
    "Rent": {
      "quantity": "25.000",
      "cost": "50.000"
    },
    "Purchased": {
      "quantity": "0.0",
      "cost": "0.0"
    }
  },
  "Item 4": {
    "Rent": {
      "quantity": "5.000",
      "cost": "80.000"
    },
    "Purchased": {
      "quantity": "0.0",
      "cost": "0.0"
    }
  }
}

The data is printed into a prepared template. Leaving it aside, what I want is for the "Purchased" and "Rent" sections of each item to be alphabetically sorted. Items 1 and 2 are proper here but items 3 and 4 are not. The issue is that from the server items can come with different kinds of data. For e.g. Item 2 came only with Purchased, so a Rent component with 0,0 was added.

I have seen a few string sorting functions here on so but they are for single arrays and I have failed to adopt them here.

Jon Uleis
  • 17,693
  • 2
  • 33
  • 42
Nie Selam
  • 1,343
  • 2
  • 24
  • 56
  • What are you trying to do with this object? Object keys don’t have an order, so it’s impossible to sort them. If the order is important for the data itself, use an array. – Sebastian Simon Sep 17 '17 at 20:10
  • @There is a template that is developed someone else (i have no idea how it works) but i pass the object and it places in the right place in tabular format after it does some calculations. The problem now is the template expects Purchase to come before Rent. So the above object gives incorrect result, that's all. Anyway, thanks. – Nie Selam Sep 17 '17 at 20:13
  • 3
    There is no “before” or “after” in object properties. If the template relies on some kind of order in object properties, then don’t use it. – Sebastian Simon Sep 17 '17 at 20:15
  • Is the template rendered client-side (using JS) or server-side? While Object keys don't have a _(predictable)_ order in JS, they do in PHP, and there you can sort/reorder them as long as they do not go through JS (unless you leave them as a JSON string before sending them to a server) – blex Sep 17 '17 at 20:22
  • @blex the template is all in JS. I am looking at it now but it is overly complex and undocumented. The backend is python/django that sends JSON data. The problem is some items have just Purchased so the front end (me) adds Rent with 0 values to meet the template's expectation. Anyway, I am going to look for ways in the back end, I guess. – Nie Selam Sep 17 '17 at 20:29
  • Possible duplicate of [Is there a way to sort/order keys in JavaScript objects?](https://stackoverflow.com/questions/9658690/is-there-a-way-to-sort-order-keys-in-javascript-objects) – Alex McMillan Sep 17 '17 at 20:32
  • https://stackoverflow.com/questions/5467129/sort-javascript-object-by-key – Alex McMillan Sep 17 '17 at 20:33
  • Ok. You might be able to find a workaround, but it's generally a bad idea to rely on undocumented libraries, templates, etc. because if you run into problems, it will be much harder to find solutions. Plus, it seems to be poorly constructed, if it relies on property order. – blex Sep 17 '17 at 20:33
  • I hear you guys. Time to change the template engine in use. Thanks fellas. – Nie Selam Sep 17 '17 at 20:41

3 Answers3

0

// So you mean you basically want 'Purchased' to come before 'Rent'? As others have said, objects don't really have order. So if you wanted control over order you could probably map this to an array, using lodash or something similar e.g.

_ = require('lodash');

_.map(properties, (property, index) => {
let thisProp = {};
thisProp[`Item ${index + 1}`] = [{Purchased: property.Purchased}, {Rent: property.Rent}];
return thisProp;
});

This will return data in the form:

[
{
    "Item 1": [
        {
            "Purchased": {
                "quantity": "5.000",
                "cost": "80.000"
            }
        },
        {
            "Rent": {
                "quantity": "45.000",
                "cost": "25200.000"
            }
        }
    ]
},
{
    "Item 2": [
        {
            "Purchased": {
                "quantity": "35.000",
                "cost": "25000.000"
            }
        },
        {
            "Rent": {
                "quantity": "0.0",
                "cost": "0.0"
            }
        }
    ]
}
] //etc.
-1

You can do what @Jonny Rathbone suggested also without having to use any further library. Just do

for (var p in DAT) 
  DAT[p]={Purchased:DAT[p].Purchased,
          Rent:DAT[p].Rent};

A JSON.stringify() now lists the properties in the desired order. But, as @xufox and @blex have commented already: the order of properties in JavaScript is not really defined, so the result achieved here might not be sustainable in all browsers or future versions of JavaScript.

Carsten Massmann
  • 26,510
  • 2
  • 22
  • 43
-1

The following snippet does what you requested, in the most popular browsers. But, as already mentioned below your question, it is not enforced by the specification that objects keep their order.

const data = {
 "Item 1": {
    "Purchased": {
      "quantity": "5.000",
      "cost": "80.000"
    },
    "Rent": {
      "quantity": "45.000",
      "cost": "25200.000"
    }
  },
  "Item 2": {
    "Purchased": {
      "quantity": "35.000",
      "cost": "25000.000"
    },
    "Rent": {
      "quantity": "0.0",
      "cost": "0.0"
    }
  },
  "Item 3": {
    "Rent": {
      "quantity": "25.000",
      "cost": "50.000"
    },
    "Purchased": {
      "quantity": "0.0",
      "cost": "0.0"
    }
  },
  "Item 4": {
    "Rent": {
      "quantity": "5.000",
      "cost": "80.000"
    },
    "Purchased": {
      "quantity": "0.0",
      "cost": "0.0"
    }
  }
}

function sortItem(item) {
  const sortedKeys = Object.keys(item).sort()
  return sortedKeys.reduce((accu, key) => ({ ...accu, [key]: item[key] }), {})
}

const result = Object.keys(data).reduce((accu, key) => ({ ...accu, [key]: sortItem(data[key]) }), {})

console.log(result)

Thus I recommend the following solution which makes use of arrays (order in result always guaranteed):

const data = {
 "Item 1": {
    "Purchased": {
      "quantity": "5.000",
      "cost": "80.000"
    },
    "Rent": {
      "quantity": "45.000",
      "cost": "25200.000"
    }
  },
  "Item 2": {
    "Purchased": {
      "quantity": "35.000",
      "cost": "25000.000"
    },
    "Rent": {
      "quantity": "0.0",
      "cost": "0.0"
    }
  },
  "Item 3": {
    "Rent": {
      "quantity": "25.000",
      "cost": "50.000"
    },
    "Purchased": {
      "quantity": "0.0",
      "cost": "0.0"
    }
  },
  "Item 4": {
    "Rent": {
      "quantity": "5.000",
      "cost": "80.000"
    },
    "Purchased": {
      "quantity": "0.0",
      "cost": "0.0"
    }
  }
}

function sortItem(item) {
  const sortedKeys = Object.keys(item).sort()
  return sortedKeys.reduce((accu, key) => [...accu, { key, ...item[key] }], [])
}

const sortedKeys = Object.keys(data).sort()
const result = sortedKeys.reduce((accu, key) => [...accu, { key, info: sortItem(data[key]) }], [])

console.log(result)
ideaboxer
  • 3,863
  • 8
  • 43
  • 62