অ্যান্ডসোর.জেএস সহ অবজেক্ট থেকে খালি বৈশিষ্ট্য / মিথ্যা মানগুলি সরান


84

আমার বেশ কয়েকটি সম্পত্তি সহ একটি বস্তু রয়েছে। মিথ্যা মান রয়েছে এমন যে কোনও বৈশিষ্ট্য আমি মুছে ফেলতে চাই।

এটি compactঅ্যারে দিয়ে অর্জন করা যেতে পারে তবে অবজেক্টগুলির কী হবে?


কপি-পেস্ট ভান্ডার জুড়ে এটি এড়াতে, আপনি ব্যবহার করতে পারেন বিট করতে এই উপাদানটি আমদানি (যা 3 ক্ষণস্থায়ী & MIT- র লাইসেন্স পরীক্ষার আছে)। আপনি এই এনপিএম প্যাকেজটিও চেষ্টা করতে পারেন (এটি কোনও ছোট উপাদানগুলির জন্য ওভারকিল হতে পারে)।
Yoni

উত্তর:


47

আপনি নিজের আন্ডারস্কোর প্লাগইন তৈরি করতে পারেন (মিক্সিন):

_.mixin({
  compactObject: function(o) {
    _.each(o, function(v, k) {
      if(!v) {
        delete o[k];
      }
    });
    return o;
  }
});

এবং তারপরে এটি স্থানীয় আন্ডারস্কোর পদ্ধতি হিসাবে ব্যবহার করুন:

var o = _.compactObject({
  foo: 'bar',
  a: 0,
  b: false,
  c: '',
  d: null,
  e: undefined
});

Update

As @AndreiNeculau pointed out, this mixin affects the original object, while the original compact underscore method returns a copy of the array.
To solve this issue and make our compactObject behave more like it's cousin, here's a minor update:

_.mixin({
  compactObject : function(o) {
     var clone = _.clone(o);
     _.each(clone, function(v, k) {
       if(!v) {
         delete clone[k];
       }
     });
     return clone;
  }
});

1
Since the question has an underscore reference, it would be good to mention that this does not behave like _.compact. It will delete properties, rather than create a shallow clone with truthy values only. See stackoverflow.com/a/19750822/465684 below
Andrei Neculau

@AndreiNeculau You're right! I seem to have missed that earlier. See my updated answer.
gion_13

3
Why first copy all the properties of an object, then loop through them and delete falsy ones? That's unperformant. Moreover, using delete is generally discouraged as it immediately exposes properties with the same name from the prototype chain and also hurts performance due to "hidden classes" (V8) - changing the object structure causes the engine to do extra work. The best and shortest solution would be _.pick(o, _.identity).
Radko Dinev

171

Since Underscore version 1.7.0, you can use _.pick:

_.pick(sourceObj, _.identity)

Explanation

The second parameter to _.pick can be a predicate function for selecting values. Values for which the predicate returns truthy are picked, and values for which the predicate returns falsy are ignored.

pick _.pick(object, *keys)

Return a copy of the object, filtered to only have values for the whitelisted keys (or array of valid keys). Alternatively accepts a predicate indicating which keys to pick.

_.identity is a helper function that returns its first argument, which means it also works as a predicate function that selects truthy values and rejects falsy ones. The Underscore library also comes with a bunch of other predicates, for instance _.pick(sourceObj, _.isBoolean) would retain only boolean properties.

If you use this technique a lot, you might want to make it a bit more expressive:

var pickNonfalsy = _.partial(_.pick, _, _.identity); // Place this in a library module or something
pickNonfalsy(sourceObj);

Underscore version 1.6.0 provided _.pick as well, but it didn't accept a predicate function instead of a whitelist.


2
Special thanks for mentioning _.identity function, very handy.
ivkremer

9
This has been extremely handy! It's also possible to use _.omit(sourceObj, _.isUndefined) to remove only undefined values (allowing false, null, 0).
Ben Patterson

1
Its also possible to do pick(obj, Boolean) to eliminate falsey values that same approach can be used when arr.filter(Boolean) to clean an array from falsey values...
David Chase

3
In ES6, this turns into _.pick(sourceObj, prop => prop)
Deniz Ozger

16
In lodash 4.4.0 _.pick works with property names, for this functionality as mentioned in post use _.pickBy
zooblin

46

Quick 'n Clear: _.omitBy( source, i => !i );

This is stated in an inverse fashion to Emil's answer. This way imho reads clearer; it's more self explanatory.

Slightly less clean if you don't have the luxury of ES6: _.omitBy( source, function(i){return !i;});

Alternate: _.omitBy( source, _.isEmpty)

Using _.isEmpty, instead of _.identity for truthiness, will also conveniently remove empty arrays and objects from the collection and perhaps inconveniently remove numbers and dates. Thus the outcome is NOT an exact answer to the OP's question, however it could be useful when looking to remove empty collections.


8
In Lodash 4.0, this functionality is now under omitBy. lodash.com/docs#omitBy
JackMorrissey

3
I believe this is the same as: _.pick(source, i => i); which avoids the negation
Jeff Lowery

2
@JeffLowery This is even better, in Lodash, because the default predicate is the identity function! _.pickBy(source) is all that's needed.
Shibumi

Note: Numbers are considered empty. _.isEmpty(5) === true. Thus values that are numbers will be dropped.
Sir.Nathan Stassen

21

With lodash's transform,

_.transform(obj, function(res, v, k) {
  if (v) res[k] = v;
});

23
whit lodash's _.pick(obj, _.identity); shorter ^_^
evilive

This answer or @evilive's comment under it IS the answer.
Radko Dinev

2
a shorter variation, based on the above comment, would be var compactObject = _.partialRight(_.pick, _.identity);
zaboco


yse, _.pickBy(object) is all you need
wdetac


9

You can create a shallow clone:

_(obj).reduce(function(a,v,k){ 
     if(v){ a[k]=v; } 
     return a; 
},{});

5

for object use delete.

for(var k in obj){

  if(obj.hasOwnProperty(k) && !obj[k]){
    delete obj[k];
  }
}

since he wants an underscore solution, you could iterate over the array using one of underscore's methods
gion_13

5

Suddenly I needed create a function to remove recursively falsies. I hope this helps. I'm using Lodash.

var removeFalsies = function (obj) {
    return _.transform(obj, function (o, v, k) {
        if (v && typeof v === 'object') {
            o[k] = _.removeFalsies(v);
        } else if (v) {
            o[k] = v;
        }
    });
};

_.mixin({ 'removeFalsies': removeFalsies });

Then you can use it:

var o = _.removeFalsies({
  foo: 'bar',
  a: 0,
  b: false,
  c: '',
  d: null,
  e: undefined,
  obj: {
    foo: 'bar',
    a: 0,
    b: false,
    c: '',
    d: null,
    e: undefined
  }
});

// {
//   foo: 'bar',
//   obj: {
//     foo: 'bar'
//   }
// }

1

To add to gion_13's answer:

_.mixin({
  compactObject : function(o) {
     var newObject = {};
     _.each(o, function(v, k) {
       if(v !== null && v !== undefined) {
         newObject[k] = v
       }
     });
     return newObject;
  }
});

This one creates a new object and adds keys and values instead of cloning everything and deleting key-value pairs. Minor difference.

But more importantly, checks explicitly for null and undefined instead of falsey, which will delete key-value pairs that have false as a value.



-1

Although _.compact is documented for use in arrays. It seems to work for objects too. I just ran the following in chrome, opera and firefox consoles:

var obj = {first: 1, second: null, third: 3, fourth: function(){return 5}}
undefined
_.compact(obj)

[1, 3, function()]

UPDATE: As the sample indicates calling _.compact on an object will drop the keys and return a compacted array.


1
But it still returns an array. The keys are lost.
Turadg

1
You're right. Do I delete my answer then? Or does stackoverflow prefer something else?
tzvi

2
I don't know a community preference, but if you're fine with leaving it could have value of preventing someone else from adding a similar answer.
Turadg
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.