Javascript, Transforming object with underscore (or not)

I am looking to prepare an object for send. It initially looks like so :

var myObj = {"state":{"Saved":true,"Committed":false,"Published":false},"discipline":{"Marketing":true}};

And needs to be change via looking at the inner objects and turning it into an array of keys of the objects who's values are true. So in this example it would change into this :

 {"state":["Saved"],"discipline":["Marketing"]};

(committed and published were removed because they were set to false. )

Here is what I've tried so far:

                function mutate() {
                   //map obj
                    return _.map(myObj, function(object){ 
                     //pluck keys that have = true
                        return _.keys(_.pick(object[0], Boolean));
                     });
                }

Struggling with this a bit, and how to traverse and build this correctly. I am using underscore - but plain javascript is fine if it makes more sense. Thanks!

Answers:

Answer

You can solve this in vanilla JS using map, reduce, and Object.keys:

var myObj = {
  "state": {
    "Saved": true,
    "Committed": false,
    "Published": false
  },
  "discipline": {
    "Marketing": true
  }
};

var output = Object.keys(myObj).reduce(function(p, collection) {
  var values = myObj[collection];
  p[collection] = Object.keys(values).filter(function(key) {
    return values[key] === true;
  });
  return p;
}, {});

document.getElementById('results').textContent = JSON.stringify(output);
<pre id="results"></pre>

This works by:

  1. Taking the keys of the outer object and reducing each to a collection of true values on that key.
  2. In the reduce, we:
    1. Filter only true values
    2. Return only the key for each value

The algorithm is fairly simple and should work with almost any object you throw at it. You can change the filter easily and there may be a few optimizations you could try out.

The equivalent with underscore would be:

    var myObj = {
      "state": {
        "Committed": false,
        "Saved": true,
        "Published": false
      },
      "discipline": {
        "Marketing": true
      }
    };

    var output = _.reduce(myObj, function(p, values, collection) {
      p[collection] = _.chain(values).map(function(value, key) {
        console.log('filter', arguments);
        if (value === true) {
          return key;
        }
      }).filter(function(it) {
        return !!it;
      }).value();
      return p;
    }, {});

    document.getElementById('results').textContent = JSON.stringify(output);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<pre id="results"></pre>

Answer

You were nearly there with your answer. Use _.mapObject to retain the keys instead of map.

    var result = _.mapObject(myObj, function(value){
        return _.keys(_.pick(value, Boolean));
    });

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us Javascript

©2020 All rights reserved.