Hello coders,
I thought we could explore, as a thought experiment, how one might go about reconstruction certain functionality of the .sort() method in javascript.
The challenge
Let's say we are creating a webpage that displays world currencies and their values. The finished project may look something like this:
In order to build this page, we fetched the json file from a free online api such as api.coingecko.com. The code for this fetch request looks like this:
let jsonOBJ = {}
fetch(
'https://api.coingecko.com/api/v3/exchange_rates'
).then(
res=>res.json()
).then(
data=> {jsonOBJ = data})
Let's now look at a truncated version of the resulting json object:
let jsonOBJ = {"rates": {
"btc": {
"name": "Bitcoin",
"unit": "BTC",
"value": 1.0,
"type": "crypto"
},
"ltc": {
"name": "Litecoin",
"unit": "LTC",
"value": 372.614,
"type": "crypto"
},
"eth": {
"name": "Ether",
"unit": "ETH",
"value": 13.371,
"type": "crypto"
}
}}
Great. Now here comes the tricky part. How would we go about reordering this object by one of the values?
Say, for example, we want to sort the object such that objects in the "rates" object are sorted by the "value" subfield.
The resulting object should look like this:
let jsonOBJ = {"rates": {
"btc": {
"name": "Bitcoin",
"unit": "BTC",
"value": 1.0,
"type": "crypto"
},
"eth": {
"name": "Ether",
"unit": "ETH",
"value": 13.371,
"type": "crypto"
},
"ltc": {
"name": "Litecoin",
"unit": "LTC",
"value": 372.614,
"type": "crypto"
}
}
The solution walkthrough
Let's break this problem into a few different chunks.
Task 1 : create an array of the sorting items
Fist off, lets create a separate array of all the
values from the field we wish to sort. This will
come in handy later on.
//create the new array
let sortArray = []
/*for each key in the unsorted object, find the corresponding sorting value field and push that item into the empty array "sortArray"*/
Object.keys(jsonOBJ.rates).map(
e=>sortArray.push(jsonOBJ.rates[e]
['value'])
)
This results in the following values for sortArray:
sortArray = [1.0, 372.614, 13.371]
Finally, let's sort those values the way we would ultimately like our json object to be sorted. In this case, we want them sorted numerically from least to greatest:
sortArray = sortArray.sort((a,b) => a-b)
console.log(sortArray)
//[1, 13.371, 372.614]
Excellent! Now we have an array which consists of values from the json object. Those values are are from the field by which we wish to sort. And they are sorted in the desired arrangement.
Build the sorted Object
Here is where things get a little bit trickier. Using our sorted array of values,
sortArray = [1, 13.371, 372.614]
we are going to iterate through this sortArray, and check each element against the original nested json objects, looking for a match. When we get a match, we will add that nested object to a new object. Since we will be iterating through the sortArray in the order we wish our data to be sorted in, the resulting new object will likewise be in the correct order.
let newOBJ = {}
for (let i in sortArray){
for (let j in jsonOBJ.rates )
{
if (jsonOBJ.rates[j]['value'] === sortArray[i]){
newOBJ[j] = jsonOBJ.rates[j];
//deleting the nested jsonOBJ object here prevents double entries.
delete jsonOBJ.rates[j];
}
}
}
//replace original with newObj
jsonOBJ['rates']=newOBJ
That should do it. If we console.log(jsonOBJ) now we should see the correct order of nested arrays:
{"rates": {
"btc": {
"name": "Bitcoin",
"unit": "BTC",
"value": 1.0,
"type": "crypto"
},
"eth": {
"name": "Ether",
"unit": "ETH",
"value": 13.371,
"type": "crypto"
},
"ltc": {
"name": "Litecoin",
"unit": "LTC",
"value": 372.614,
"type": "crypto"
}
}
Great! These entries are indeed in the correct order.
Looking ahead
One thing that is really cool about this approach is that we could sort the json object by whichever nested field (no matter how nested that field might be) and by whichever sorting convention we like.
Would you rather sort the same object alphabetically by the nested "name" field. No problem. Simply cntrl+f and replace the string "value" with the string "name" and replace the sorting rule:
sortArray = sortArray.sort((a,b) => a-b)
with
sortArray = sortArray.sort()
As a function
Of course, what good is being able to write this algorithm if we cannot compile it in to a reusable function that can handle any future situation we may encounter.
Let's take a look at this algorithm, expressed as a function, which takes as it's arguments (a) the original, unsorted object (b) the key value of the nested field we wish to sort by and (c) the sorting function, and returns the sorted Object:
function sortByValue(obj, value, sortFunction){
let sortArray = []
let newOBJ = {}
//add values, in the order they are in now, to sortArray
Object.keys(obj).map(key=>{
sortArray.push(obj[key][value])}
)
//Perform the sortFunction
sortFunction(sortArray)
//Cross-iterate sortArray with original object and populate the new Object
for (let i in sortArray){
for (let j in obj ){
if (obj[j][value] === sortArray[i]){
newOBJ[j] = obj[j]}
}
}
return newOBJ
}
It is important to note that the above function would only work if the sorting key is 1 nest deep in the object. But it's easy to see how this might be extended to handle other situations.
This wraps up this blog post. See ya!
Top comments (0)