Frequency Sort the array of objects in JS and if the frequency corresponds to the base of the object

advertisements

I have Array of objects

[
    {"X" : {
        "price" : "5"
      }
    },
    {"Y" : {
        "price" : "3"
      }
    },
    {"Y" : {
        "price" : "3"
      }
    },
    {"Z" : {
        "price" : "4"
      }
    },
    {"Q" : {
        "price" : "2"
      }
    },
    {"X" : {
        "price" : "5"
      }
    },
    {"Z" : {
        "price" : "4"
      }
    },
    {"X" : {
        "price" : "5"
      }
    }
]

I want to frequency Sort the array so that i get like [object:count]

How do i get the array to Transform arr to the format:

// [{key: x, count: 3, price: 5}},{key: y:, count: 2, price: 3}

[{x:3},{y:2},{z:2},{q:1}]

But the problem i am facing is if the frequency matches then the sort has to check the object's property i:e in this case the price and if the price is more than the other matching element that should be given weight age so in this case z price is more than y so z should be given priority.

[{x:3},{z:2},{y:2},{q:1}]

This is what i have tried so far:

var a = ["x", "v"], b = ["x", "y"], c = ["d", "y"];
var d = a.concat(b, c);

function sortByFrequency(array) {
    var frequency = {};

    array.forEach(function(value) { frequency[value] = 0; });

    var uniques = array.filter(function(value) {
        return ++frequency[value] == 1;
    });

    return uniques.sort(function(a, b) {
        return frequency[b] - frequency[a];
    });
}

var frequency = sortByFrequency(d);

console.log(frequency);
.as-console-wrapper{min-height:100%}

Update after answer

I still donot know how to transform the array to this format

   var arr = [
{"key":"X",
    "price" : "5",
    "count" :"3"
  }
,
{"key":"Y",
    "price" : "3",
    "count" :"2"
  }
,
{"key":"Z",
    "price" : "4",
    "count" : "2"
  }

];

var r = _.sortBy(_.sortBy(arr, 'price'), 'count'); 

console.log(JSON.stringify(r));
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js"></script>

now it works but how to get the object to this format from array


Try this one using reduce and then sort.

Explaination

In order to achieve the desired result you can break down the task in below steps.

1. Grouping - Group by the items in the array using the Property names (x,y,z)
2. Sorting - Sort the Result from Step1 in descending order where the first criteria is the count of items and the second criteria is the price.

1.Grouping - There isn't a native group by function in javascript. Therefore, we can make use of the reduce function which basically runs a function over the sequence of array and also returns the accumulated value.

a. In the reduce function, the accumulator will start with an empty array as mentioned in comments in code towards the end of the reduce function.

b. We get the property name like "x", "y", "z" by traversing the object. Also, we use the zeroth index as there is only one property like "x", "y", "z".

c. After that we check if the property is already in the Array or not.

d. If the Property is not in the array, then we need to add the property to the Array.

e. We create a object to handle the count and price information which would be used later.

f. If the Property already exists as mentioned in step c, then we need to increment the count of that property elementInArray[propName].count++;

2. Sorting
a. sort function takes a comparer function. In that function we compare the 2 items firsly by their count. If count is equal then we compare them by the price.

var arr = [
    {"X" : {
        "price" : "5"
      }
    },
    {"Y" : {
        "price" : "3"
      }
    },
    {"Y" : {
        "price" : "3"
      }
    },
    {"Z" : {
        "price" : "4"
      }
    },
    {"Q" : {
        "price" : "2"
      }
    },
    {"X" : {
        "price" : "5"
      }
    },
    {"Z" : {
        "price" : "4"
      }
    },
    {"X" : {
        "price" : "5"
      }
    }
];

var frequency = arr.reduce(function (accumulatorObject, currentValue) {
  var propName = Object.keys(currentValue)[0];
  var elementInArray = accumulatorObject.find((element) => Object.keys(element)[0] === propName);
  if (elementInArray) {
    elementInArray[propName].count++;
  }
  else {
    var newObject = {};
    newObject[propName]  = {};
    newObject[propName].count = 1;
    newObject[propName].price = +currentValue[propName].price;
    accumulatorObject.push(newObject);
 }
  return accumulatorObject;
}, []); //  // Accumulator starts with Empty array. 

frequency.sort(function(first,second){
    var diff =  second[Object.keys(second)].count - first[Object.keys(first)].count;
    if( diff === 0) {
        return second[Object.keys(second)].price - first[Object.keys(first)].price;
    }
return diff;});
console.log(frequency);