Search code examples
javascriptlodashpurely-functional

How to ration amount in purely functional style


I need to distribute certain amounts to array of people according to their score. The rule is that their demands are met according to their position with whatever remains. In JavaScript using Lo-Dash (JSBin):

var amount = 1000,
  people = [
    { name : 'Joe', score: 40, demand: 400},
    { name : 'Sue', score: 30, demand: 350},
    { name : 'Kim', score: 25, demand: 300},
    { name : 'Ron', score: 20, demand: 250}
  ];

function  distribute(people, amount){
   return _.map(_.sortBy(people,'need'),function(person){      
     var ration = Math.min(person.demand,amount); 
     amount -= ration; // This is the state (mutation) that I want to avoid
     return _.assign(person,{ ration: ration})
 });
}
console.log(distribute(people, amount));

Result:

[{  demand: 400,  name: "Joe",  ration: 400,  score: 40}, 
 {  demand: 350,  name: "Sue",  ration: 350,  score: 30}, 
 {  demand: 300,  name: "Kim",  ration: 250,  score: 25}, 
 {  demand: 250,  name: "Ron",  ration:   0,  score: 20}]

Since the solution depends on the order, is it possible to change this code to make it purely functional?


Solution

  • The functional solution is a fold:

    function distribute(people, amount) {
      return _.foldl(_.sortBy(people, 'score'), function(result, person) {
        var ration = Math.min(person.demand, result.remaining);
        var resultPerson = _.assign(person, { ration: ration });
        return { people: result.people.concat(resultPerson),
                 remaining: result.remaining - ration };
      }, { people: [], remaining: amount }).people;
    }