ajmajmajma
ajmajmajma

Reputation: 14216

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!

Upvotes: 2

Views: 83

Answers (2)

Gruff Bunny
Gruff Bunny

Reputation: 27976

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));
    });

Upvotes: 1

ssube
ssube

Reputation: 48267

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>

Upvotes: 2

Related Questions