11

I have an object like so:

> Object
  > [email protected]: Array[100]
  > [email protected]: Array[4]
    > 0
       id : 132
       selected : true
    > 1
       id : 51
       selected : false

etc..

How can I use the underscore _.filter() to return back only the items where selected === true?

I've never had the need to go down to layers with _.filter(). Something like

var stuff = _.filter(me.collections, function(item) {
    return item[0].selected === true;
});

Thank you

5
  • Could you clarify the object format? It looks like a hash of arrays keyed to e-mail addresses? Commented Jul 28, 2012 at 2:22
  • that's correct, how can I clarify? Commented Jul 28, 2012 at 2:22
  • And you're trying to pull out items from the hash where all of the array elements have selected == true? Commented Jul 28, 2012 at 2:24
  • correct, just items with selected === true Commented Jul 28, 2012 at 2:24
  • Ok, still not quite sure what you're looking for but posted strategies for the two most likely cases :^) Commented Jul 28, 2012 at 2:28

6 Answers 6

10

If you want to pull all array elements from any e-mail address where selected is true, you can iterate like so:

var selected = [];

for (email in emailLists) {
    selected.concat(_.filter(emailLists[email], function (item) {
        return item.selected === true;
    }));
}

If you only want to pull the arrays where all elements are selected, you might instead do something like this:

var stuff = _.filter(me.collections, function(item) {
    return _.all(item, function (jtem) { 
        jtem.selected === true;
    });
});
Sign up to request clarification or add additional context in comments.

9 Comments

Thanks, for the first answer, what is "email in obj" and "obj[email]" the object I have is called "emailLists" given that, can you update? thx
strange, i'm getting a "Uncaught SyntaxError: Unexpected identifier "
Sure. obj should have been emailLists; email is just the key of each element in the object. Where's that error coming up? (I didn't test!) :^)
ok nice that fixed the error. selected is always coming back as '[]'
I did a console.log inside, and "console.log(item.selected === true)" is correctly being logged as either true or false. For some reason it's not making it to the selected var
|
5

Underscore's filter method will work on an object being used as a hash or dictionary, but it will return an array of the object's enumerable values and strip out the keys. I needed a function to filter a hash by its values that would preserve the keys, and wrote this in Coffeescript:

hash_filter: (hash, test_function) ->
  keys = Object.keys hash

  filtered = {}
  for key in keys
    filtered[key] = hash[key] if test_function hash[key]
  filtered

If you're not using Coffeescript, here's the compiled result in Javascript, cleaned up a little:

hash_filter = function(hash, test_function) {
  var filtered, key, keys, i;
  keys = Object.keys(hash);
  filtered = {};
  for (i = 0; i < keys.length; i++) {
    key = keys[i];
    if (test_function(hash[key])) {
      filtered[key] = hash[key];
    }
  }
  return filtered;
}


hash = {a: 1, b: 2, c: 3};
console.log((hash_filter(hash, function(item){return item > 1;})));
// Object {b=2, c=3}

TL; DR: Object.keys() is great!

2 Comments

I added the key in as a second parameter, as Underscore's _.filter() does. Hope that's cool! :)
_.filter for object with keys is just _.pick
1

I have an object called allFilterValues containing the following:

{"originDivision":"GFC","originSubdivision":"","destinationDivision":"","destinationSubdivision":""}

This is ugly but you asked for an underscore based way to filter an object. This is how I returned only the filter elements that had non-falsy values; you can switch the return statement of the filter to whatever you need:

    var nonEmptyFilters = _.pick.apply({}, [allFilterValues].concat(_.filter(_.keys(allFilterValues), function(key) {
        return allFilterValues[key];
    })));

Output (JSON/stringified):

{"originDivision":"GFC"}

Comments

1

@Dexygen was right to utilize _.pick but a cleaner solution is possible because the function also accepts a predicate

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

(highlight is mine)

Here's a real life example I've used in a project

_.pick({red: false, yellow: true, green: true}, function(value, key, object) {
    return value === true;
});
// {yellow: true, green: true}

Comments

1
const obj = {
    1 : { active: true },
    2 : { active: false },
    3 : { active: false },
}

let filtered = Object.entries(obj).reduce((acc, current) => {
    const currentEntry = current[1];
    const currentKey = current[0];
    //here you check condition
    if (currentEntry.active) {
      return {
        ...acc,
        [currentKey]: currentEntry
      }
    }
    return acc;
}, {})

There is a rule of thumb, if you need to achieve something really exotic look up into reducer it can solve almost all problems related to objects, it's a bit tricky to get used to it, but trust me thorough reading of documentation gonna pay off.

Comments

-1

Maybe you want a simplest way

_.filter(me.collections, { selected: true})

1 Comment

This answer is partially correct; you can use {selected: true} as a predicate in Underscore, for example with _.filter or _.some. In this case, it is not the whole story because the objects with {selected: true} are embedded in a larger object.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.