Sort by Values Algorithm
Published: 2022-05-11 17:59:29

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/69gmgn7douojmxs6i2jt.png)

In order to build this page, we fetched the json file from a free online api such as [api.coingecko.com](https://api.coingecko.com/api/v3/exchange_rates). The code for this fetch request looks like this:


```javascript 
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:

```javascript

 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:
```javascript

 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.

``` javascript
//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:
``` javascript
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: 

``` javascript
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,
``` javascript
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.

``` javascript
 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:

``` javascript
{"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:

```javascript
sortArray = sortArray.sort((a,b) => a-b)
```
with
```javascript
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:
 
``` javascript

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!