DEV Community

JPStupfel
JPStupfel

Posted on • Updated on

Sort by Values Algorithm

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:

Image description

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})
Enter fullscreen mode Exit fullscreen mode

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"
}
   }}
Enter fullscreen mode Exit fullscreen mode

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"
    }

   }
Enter fullscreen mode Exit fullscreen mode

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'])
        )
Enter fullscreen mode Exit fullscreen mode

This results in the following values for sortArray:

sortArray = [1.0, 372.614, 13.371]
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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"
    }

   }
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

with

sortArray = sortArray.sort()
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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!

Latest comments (0)