First of all, it's considered bad practice to extend Object.prototype. Instead, provide your feature as stand-alone function, or if you really want to extend a global, provide it as utility function on Object, just like there already are Object.keys, Object.assign, Object.is, ...etc.
I provide here several solutions:
- Using
reduceandObject.keys - As (1), in combination with
Object.assign - Using
mapand spread syntax instead ofreduce - Using
Object.entriesandObject.fromEntries
1. Using reduce and Object.keys
With reduce and Object.keys to implement the desired filter (using ES6 arrow syntax):
Object.filter = (obj, predicate) =>
Object.keys(obj)
.filter( key => predicate(obj[key]) )
.reduce( (res, key) => (res[key] = obj[key], res), {} );
// Example use:
var scores = {
John: 2, Sarah: 3, Janet: 1
};
var filtered = Object.filter(scores, score => score > 1);
console.log(filtered);
Note that in the above code predicate must be an inclusion condition (contrary to the exclusion condition the OP used), so that it is in line with how Array.prototype.filter works.
2. As (1), in combination with Object.assign
In the above solution the comma operator is used in the reduce part to return the mutated res object. This could of course be written as two statements instead of one expression, but the latter is more concise. To do it without the comma operator, you could use Object.assign instead, which does return the mutated object:
Object.filter = (obj, predicate) =>
Object.keys(obj)
.filter( key => predicate(obj[key]) )
.reduce( (res, key) => Object.assign(res, { [key]: obj[key] }), {} );
// Example use:
var scores = {
John: 2, Sarah: 3, Janet: 1
};
var filtered = Object.filter(scores, score => score > 1);
console.log(filtered);
3. Using map and spread syntax instead of reduce
Here we move the Object.assign call out of the loop, so it is only made once, and pass it the individual keys as separate arguments (using the spread syntax):
Object.filter = (obj, predicate) =>
Object.assign(...Object.keys(obj)
.filter( key => predicate(obj[key]) )
.map( key => ({ [key]: obj[key] }) ) );
// Example use:
var scores = {
John: 2, Sarah: 3, Janet: 1
};
var filtered = Object.filter(scores, score => score > 1);
console.log(filtered);
4. Using Object.entries and Object.fromEntries
As the solution translates the object to an intermediate array and then converts that back to a plain object, it would be useful to make use of Object.entries (ES2017) and the opposite (i.e. create an object from an array of key/value pairs) with Object.fromEntries (ES2019).
It leads to this "one-liner" method on Object:
Object.filter = (obj, predicate) =>
Object.fromEntries(Object.entries(obj).filter(predicate));
// Example use:
var scores = {
John: 2, Sarah: 3, Janet: 1
};
var filtered = Object.filter(scores, ([name, score]) => score > 1);
console.log(filtered);
The predicate function gets a key/value pair as argument here, which is a bit different, but allows for more possibilities in the predicate function's logic.
Answer from trincot on Stack OverflowFirst of all, it's considered bad practice to extend Object.prototype. Instead, provide your feature as stand-alone function, or if you really want to extend a global, provide it as utility function on Object, just like there already are Object.keys, Object.assign, Object.is, ...etc.
I provide here several solutions:
- Using
reduceandObject.keys - As (1), in combination with
Object.assign - Using
mapand spread syntax instead ofreduce - Using
Object.entriesandObject.fromEntries
1. Using reduce and Object.keys
With reduce and Object.keys to implement the desired filter (using ES6 arrow syntax):
Object.filter = (obj, predicate) =>
Object.keys(obj)
.filter( key => predicate(obj[key]) )
.reduce( (res, key) => (res[key] = obj[key], res), {} );
// Example use:
var scores = {
John: 2, Sarah: 3, Janet: 1
};
var filtered = Object.filter(scores, score => score > 1);
console.log(filtered);
Note that in the above code predicate must be an inclusion condition (contrary to the exclusion condition the OP used), so that it is in line with how Array.prototype.filter works.
2. As (1), in combination with Object.assign
In the above solution the comma operator is used in the reduce part to return the mutated res object. This could of course be written as two statements instead of one expression, but the latter is more concise. To do it without the comma operator, you could use Object.assign instead, which does return the mutated object:
Object.filter = (obj, predicate) =>
Object.keys(obj)
.filter( key => predicate(obj[key]) )
.reduce( (res, key) => Object.assign(res, { [key]: obj[key] }), {} );
// Example use:
var scores = {
John: 2, Sarah: 3, Janet: 1
};
var filtered = Object.filter(scores, score => score > 1);
console.log(filtered);
3. Using map and spread syntax instead of reduce
Here we move the Object.assign call out of the loop, so it is only made once, and pass it the individual keys as separate arguments (using the spread syntax):
Object.filter = (obj, predicate) =>
Object.assign(...Object.keys(obj)
.filter( key => predicate(obj[key]) )
.map( key => ({ [key]: obj[key] }) ) );
// Example use:
var scores = {
John: 2, Sarah: 3, Janet: 1
};
var filtered = Object.filter(scores, score => score > 1);
console.log(filtered);
4. Using Object.entries and Object.fromEntries
As the solution translates the object to an intermediate array and then converts that back to a plain object, it would be useful to make use of Object.entries (ES2017) and the opposite (i.e. create an object from an array of key/value pairs) with Object.fromEntries (ES2019).
It leads to this "one-liner" method on Object:
Object.filter = (obj, predicate) =>
Object.fromEntries(Object.entries(obj).filter(predicate));
// Example use:
var scores = {
John: 2, Sarah: 3, Janet: 1
};
var filtered = Object.filter(scores, ([name, score]) => score > 1);
console.log(filtered);
The predicate function gets a key/value pair as argument here, which is a bit different, but allows for more possibilities in the predicate function's logic.
Never ever extend Object.prototype.
Horrible things will happen to your code. Things will break. You're extending all object types, including object literals.
Here's a quick example you can try:
// Extend Object.prototype
Object.prototype.extended = "I'm everywhere!";
// See the result
alert( {}.extended ); // "I'm everywhere!"
alert( [].extended ); // "I'm everywhere!"
alert( new Date().extended ); // "I'm everywhere!"
alert( 3..extended ); // "I'm everywhere!"
alert( true.extended ); // "I'm everywhere!"
alert( "here?".extended ); // "I'm everywhere!"
Instead create a function that you pass the object.
Object.filter = function( obj, predicate) {
let result = {}, key;
for (key in obj) {
if (obj.hasOwnProperty(key) && !predicate(obj[key])) {
result[key] = obj[key];
}
}
return result;
};
How to Filter Array of Objects by Value in JavaScript
Return object from filter when one of the values matches
Filtering through an object and returning items through a filter
Javascript + Filter object of values - Code Review Stack Exchange
Videos
If you're working with arrays of objects in JavaScript, you may find yourself needing to filter the array based on a specific value. Luckily, JavaScript provides us with a built-in method to do just that: Array.filter() . In this article, we'll explore how to to filter an array of objects by value.
Let's say we have an array of objects representing different people, with properties like "name", "age", and "occupation". We want to filter this array to only include people who are over the age of 30. Here's how we could do it:
const people = [
{ name: "Alice", age: 25, occupation: "Engineer" },
{ name: "Bob", age: 35, occupation: "Teacher" },
{ name: "Charlie", age: 42, occupation: "Doctor" },
{ name: "Dave", age: 28, occupation: "Writer" },
];
const filteredPeople = people.filter((person) => person.age > 30);
console.log(filteredPeople);
// Output: [{ name: "Bob", age: 35, occupation: "Teacher" }, { name: "Charlie", age: 42, occupation: "Doctor" }]Here, we're using the filter() method on the people array, and passing in a function as an argument. This function takes each object in the array as its argument (which we've named person), and returns a boolean value indicating whether that object should be included in the filtered array.
In this case, we're using a simple comparison to check if the person's age is greater than 30. If it is, the function returns true, and the person is included in the filtered array. If not, the function returns false, and the person is excluded.
This is just one example of how you can use Array.filter() to filter an array of objects by value. Depending on your specific use case, you may need to use more complex comparison logic or filter on different properties of the objects in the array. But with Array.filter( as your tool, you'll be able to filter your arrays with ease.
Avoid use dictionary when you need Array
I'm not sure why you would prefer to store your Array-like data in a dictionary. I would suggest use a real Array if you need an Array.
Order of Object.keys
You may read more details about the order of Object.keys return values from this post: Does ES6 introduce a well-defined order of enumeration for object properties? The order of Object.keys is defined in ES2020. It may not work as you want in older environments.
Anyway, relay on the order of Object.keys don't seems to be a good idea to me. You may always sort the keys after Object.keys if you want though.
Use Object.assign to convert to / from Array
When you need an Array, use an Array. You can try Object.assign which convert your dictionary into Array and vice versa. (But this only applied to "when you cannot change the interface due to any reason").
function filterData(data, value) {
const arrayData = Object.assign([], data.map);
const filteredArrayData = arrayData.filter(list => list.includes(value));
const result = Object.assign({}, filteredArrayData);
return result;
}
Review
- the whole filter chain could be on basis of
valueinstead ofkeyfromdatasince there's no real use of key here
filter part
- technically your approach is perfect, just that it could be concise/readable
- you can simplify the
filteras in below snippet, simply because readability is one of the TOP priority of a good code IMHO
map part
instead of juggling the same
objectinsidereducebetween all elements we can simply get the required objects out of it.one other major thing is that
reduceas the name suggests is for when you wish to reduce N elements into exactly 1 element by some logic, which clearly isn't the case here & thus i thinkmapshould be preferred.we can use
maphere since at the end we want anarrayofobjects, so here we can returnobjectfor each key which at end gets collected asarrayapart from these the redability point again applies here as well, since this can also be simplified very much, refer the snippet to get an idea
quoting a point from Mozilla's doc on
reduce
The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in single output value.
Alternate approach
const data = {
"map": {
"0": ["abcd"],
"1": ["efgh"],
"2": ["xyz"],
"3": ["abcd", "xyz"],
}
}
const filtered = Object.values(data.map)
.filter(value => value.includes('xyz'))
// the () after the "=>" are used to wrap returned result into object
// the [i] inside ({..}) is used for setting the key dynamically
.map((value, i) => ({[i]: value}));
console.log('filtered', filtered);
- The data structure seems to be object representation of
array, so if possible prefer2D arrayoverobjectwith 0 based keys, this would make things more simple
PS: answer is updated after useful suggestions of @Toby Speight & @Graipher in comments