20

What is the best way to filter an object this way in ES6?

Starting data:

const acceptedValues = ["value1", "value3"]
const myObject = {
    prop1: "value1",
    prop2: "value2",
    prop3: "value3"
}

Expected output:

filteredObject = {
    prop1: "value1",
    prop3: "value3"
}
Rory O'Kane
  • 29,210
  • 11
  • 96
  • 131
saawsann
  • 625
  • 1
  • 6
  • 17
  • 2
    Best way in terms of what? A simple loop over the object's properties would do. – Felix Kling May 17 '17 at 13:19
  • If possible, try to capture accepted keys instead of values to make this easy. – hazardous May 17 '17 at 13:27
  • In term of efficiency mostly. A simple loop would do the trick indeed, But ES6 and "modern" array methods could make it easier. The answer with .reduce() is a nice example of that imo. – saawsann May 17 '17 at 13:34
  • Best way? Don't use an `Object` (but an `Array`) from the beginning. –  May 17 '17 at 13:36

9 Answers9

22

You can use reduce() to create new object and includes() to check if value of object exists in array.

const acceptedValues = ["value1", "value3"]
const myObject = {
  prop1: "value1",
  prop2: "value2",
  prop3: "value3"
}

var filteredObject = Object.keys(myObject).reduce(function(r, e) {
  if (acceptedValues.includes(myObject[e])) r[e] = myObject[e]
  return r;
}, {})

console.log(filteredObject)
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
  • Could you please explain why using `.filter` doesn't work in this case when I have an object? `this.activeUsers = window.users.filter( function(user) {// return ( (user.test === '0') && (user.isok === '0') ); return user.user_id === 1; });` getting the error `.filter is not a function` – Imnotapotato Apr 01 '19 at 15:07
  • @W.Doch because filter does not apply to objects, only arrays – Emobe May 05 '21 at 11:45
11

For ES6 and if

  • your task can be solved with only filtering based on keys and
  • you need static code (you know exactly, what properties you need to filter) and
  • it does not depend on the app state,

than you can use the following destructuring technique:

const myObject = {
  prop1: 'value1',
  prop2: 'value2',
  prop3: 'value3'
}
const { prop2, ...filteredObject } = myObject

console.info({ filteredObject, prop2 })

And you will have:

filteredObject: {prop1: "value1", prop3: "value3"}
prop2: "value2"
Roman
  • 19,236
  • 15
  • 93
  • 97
  • 1
    This is filtering based on the *key not matching*, whereas the question seeks to filter on the *value matching*. – billkw Jan 22 '23 at 23:19
6

Just to build on top of @Nenad Vracar good answer you could use an object instead of the Array with includes for faster lookup:

const acceptedValues = ["value1", "value3"];
const myObject = {
  prop1: "value1",
  prop2: "value2",
  prop3: "value3"
};

const lookup = acceptedValues.reduce( (memo, prop) => {
  memo[prop] = true;
  return memo;
});

const filteredObject = Object.keys(myObject).reduce((filtered, key) => {
  if(lookup[myObject[key]]){
    filtered[key] = myObject[key];
  }
  return filtered;
}, {});

console.log(filteredObject);

Nor that the includes doesn't do the job, but I thought to provide an alternative view.

MarcoL
  • 9,829
  • 3
  • 37
  • 50
5

Since I haven't seen an answer using Object.entries here's one. Note, due to Object.entries() implementation being significantly slower than Object.keys(), this will also be slower than the accepted answer, but some may prefer this for readability or extendability (easier to pass a different filtering function).

const acceptedValues = ["value1", "value3"];
const myObject = {
    prop1:"value1",
    prop2:"value2",
    prop3:"value3"
};
const filteredEntries = Object.entries(myObject).filter(([, v]) => acceptedValues.includes(v));
const filteredObject = Object.fromEntries(filteredEntries);

Or as a longish one-liner:

const filteredObject = Object.fromEntries(Object.entries(myObject).filter(([, v]) => accepted.includes(v)));
naktinis
  • 3,957
  • 3
  • 36
  • 52
  • That's the one I was looking for! I knew Object.entries would be the way to go. Good to note it's slower (but that is rarely an issue for most use cases) – Tom Auger Mar 28 '23 at 21:43
  • TypeError, Object.fromEntries is not a function – Aaron Jun 30 '23 at 18:54
  • What browser are you using? Should be supported on all modern browsers: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries#browser_compatibility – naktinis Jul 01 '23 at 09:49
4

Why not a simple for loop?

const acceptedValues = ["value1","value3"]
const myObject = {
    prop1:"value1",
    prop2:"value2",
    prop3:"value3"
};
var  filteredObject = {};
for(e in myObject) {
    if (myObject.hasOwnProperty(e)) {
      if (acceptedValues.indexOf(myObject[e]) != -1) {
          filteredObject[e] = myObject[e];
      }
    }
}
console.log(filteredObject);
gaetanoM
  • 41,594
  • 6
  • 42
  • 61
1

Using a simple for loop and get object by key.

const acceptedValues = ["value1","value3"]
const myObject = {
    prop1:"value1",
    prop2:"value2",
    prop3:"value3"
}

Object.prototype.getKeyByValue = function( value ) {
    for( var prop in this ) {
        if( this.hasOwnProperty( prop ) ) {
             if( this[ prop ] === value )
                 return prop;
        }
    }
}

for (var i in acceptedValues) {
  if (myObject.getKeyByValue(acceptedValues[i])){
    console.log(acceptedValues[i]);
  }
}
Idan
  • 5,405
  • 7
  • 35
  • 52
0
function filter(myObject){
  var obj=Object.assign({},myObject);
  Object.keys(obj).forEach(function(key) {
      if(acceptedValues.indexOf(obj[key])<0) delete obj[key];
  });
  return obj;
}
const filteredObject=filter(myObject);
Deepak
  • 850
  • 5
  • 13
0

IMO, the "best way" is the Lodash way

const filtered = _.pick(myObject, acceptedValues)

https://lodash.com/docs/4.17.10#pick

JeffD23
  • 8,318
  • 2
  • 32
  • 41
0
const newObj = {};
for(let key of Object.keys(myObject)){
  if(acceptedValues.includes(key)){
    newObj[key] = myObject[key]
  }
}
console.log(newObj);
fr7
  • 1
  • 2
    I recommend that you don't post only code as answer, but also provide an explanation what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes. – Mark Rotteveel May 27 '23 at 11:35