274

I want to remove the bad property from every object in the array. Is there a better way to do it than using a for loop and deleting it from every object?

var array = [{"bad": "something", "good":"something"},{"bad":"something", "good":"something"},...];

for (var i = 0, len = array.length; i < len; i++) {
  delete array[i].bad;
}

Just seems like there should be a way to use prototype, or something. I don’t know. Ideas?

8
  • 1
    Does not matter, the other ways cannot get any less then linear O(n). Whatever you use, will require accessing all of your array elements Commented Aug 8, 2013 at 18:42
  • Prototype? How would that help? Or are all those objects instances of the same constructor and share a common value for bad? Commented Aug 8, 2013 at 18:43
  • 1
    @Bergi I wonder if they were referring to prototypeJS, or the Array prototype, which dystroy exemplified Commented Aug 8, 2013 at 18:46
  • I'm not sure you should store array.length in a variable before looping. I'm sure you'll see it's not worth the pain if you profile. Commented Aug 8, 2013 at 18:46
  • 1
    @ZackArgyle Yes, in the general case there's nothing faster. Commented Aug 8, 2013 at 18:55

19 Answers 19

484

With ES6, you may deconstruct each object to create new one without named attributes:

const newArray = array.map(({dropAttr1, dropAttr2, ...keepAttrs}) => keepAttrs)
Sign up to request clarification or add additional context in comments.

19 Comments

Applying to the initial problem it may be const newArray = array.map(({ bad, ...item }) => item);
This is very recommended since it doesn't modify the original array (immutable operations)
This should be the accepted answer because it returns a new array, instead of overwriting the existing one.
What if the prop is dynamic? And u need to delete it on the fly?
@ИгорТашевски .map(({ [prop]: _, ...keep }) => keep)
|
193

The only other ways are cosmetic and are in fact loops.

For example :

array.forEach(function(v){ delete v.bad });

Notes:

  • if you want to be compatible with IE8, you'd need a shim for forEach. As you mention prototype, prototype.js also has a shim.
  • delete is one of the worst "optimization killers". Using it often breaks the performances of your applications. You can't avoid it if you want to really remove a property but you often can either set the property to undefined or just build new objects without the property.

11 Comments

Not much better than the loop if the loop is allowed to be "fake"-one lined too :P for(var i = 0; i < array.length ) delete array[i].bad
@Esailija Depends. I like to use forEach because I find the code more expressive (and because I stopped worrying about IE a long time ago).
Neither of them expresses "delete bad property of all objects in this array" in radically different way. forEach is generic and semantically meaningless by itself, like a for loop.
@Esailija I agree. That's why I precised it was "cosmetic". Isn't it clear in my answer ?
Unfortunate. I'll stick with the for loop which is generally faster than the forEach. And really...who cares about IE8. Thanks for the help.
|
37

I prefer to use map to delete the property and then return the new array item.

array.map(function(item) { 
    delete item.bad; 
    return item; 
});

3 Comments

Be aware that this mutates original array
In this particular case explicit return statement would not be required
array.forEach(v => delete v.bad);
25

You can follow this, more readable, not expectation raise due to key not found :

data.map((datum) => {
  return {
    'id':datum.id,
    'title':datum.login
  }
});

1 Comment

This was exactly what I needed! My objects had about 15 properties and I needed to keep 3.
23
const arr = [
  {id: 1, name: 'user1', test: 'abc'},
  {id: 2, name: 'user2', test: 'xyz'},
];

const newArr = arr.map(({test, ...rest}) => {
  return rest;
});

console.log(newArr);
// 👇️ [{id: 1, name: 'User1'},  {id: 2, name: 'User2'}]

The function we pass to the Array.map method gets invoked with each element in the array.

We destructure the test property from each object and use the rest operator (...) to get the rest of the object's properties.

We return the rest of the object's properties from the function, practically excluding the test property.

const arr = [
  {id: 1, name: 'Tom', test: 'abc'},
  {id: 2, name: 'Bob', test: 'xyz'},
];

arr.forEach(object => {
  delete object['test'];
});

console.log(arr);
// 👇️ [{id: 1, name: 'Tom'}, {id: 2, name: 'Bob'}]

2 Comments

it return null to array
Please share your code sample if possible. It helps to understand issue
18

If you use underscore.js:

var strippedRows = _.map(rows, function (row) {
    return _.omit(row, ['bad', 'anotherbad']);
});

Comments

11

For my opinion this is the simplest variant

array.map(({good}) => ({good}))

1 Comment

the question was about removing the bad, not keeping the good. If your objects have 10 fields to keep and one to remove, the above becomes really long to type.
8

A solution using prototypes is only possible when your objects are alike:

function Cons(g) { this.good = g; }
Cons.prototype.bad = "something common";
var array = [new Cons("something 1"), new Cons("something 2"), …];

But then it's simple (and O(1)):

delete Cons.prototype.bad;

Comments

8

var array = [{"bad": "something", "good":"something"},{"bad":"something", "good":"something"}];

const cleanArray = array.map(item=>{
  delete item.bad
  return item
})
console.log(cleanArray)

Comments

4

The shortest way in ES6:

array.forEach(e => {delete e.someKey});

Comments

3

This question is a bit old now, but I would like to offer an alternative solution that doesn't mutate source data and requires minimal manual effort:

function mapOut(sourceObject, removeKeys = []) {
  const sourceKeys = Object.keys(sourceObject);
  const returnKeys = sourceKeys.filter(k => !removeKeys.includes(k));
  let returnObject = {};
  returnKeys.forEach(k => {
    returnObject[k] = sourceObject[k];
  });
  return returnObject;
}

const array = [
  {"bad": "something", "good":"something"},
  {"bad":"something", "good":"something"},
];

const newArray = array.map(obj => mapOut(obj, [ "bad", ]));

It's still a little less than perfect, but maintains some level of immutability and has the flexibility to name multiple properties that you want to remove. (Suggestions welcome)

Comments

2

This works well for me!

export function removePropertiesFromArrayOfObjects(arr = [], properties = []) {
return arr.map(i => {
    const newItem = {}
    Object.keys(i).map(key => {
        if (properties.includes(key)) { newItem[key] = i[key] }
    })
    return newItem
})
}

Comments

1

I will suggest to use Object.assign within a forEach() loop so that the objects are copied and does not affect the original array of objects

var res = [];
array.forEach(function(item) { 
    var tempItem = Object.assign({}, item);
    delete tempItem.bad; 
    res.push(tempItem);
});
console.log(res);

Comments

1

ES6:

const newArray = array.map(({keepAttr1, keepAttr2}) => ({keepAttr1, newPropName: keepAttr2}))

Comments

1

If you're using the underscore.JS library:

let asdf = [{"asd": 12, "asdf": 123}, {"asd": 121, "asdf": 1231}, {"asd": 142, "asdf": 1243}]


_.map(asdf, function (row) {
    return _.omit(row, ['asd'])
})

Comments

0

There are plenty of libraries out there. It all depends on how complicated your data structure is (e.g. consider deeply nested keys)

We like object-fields as it also works with deeply nested hierarchies (build for api fields parameter). Here is a simple code example

// const objectFields = require('object-fields');

const array = [ { bad: 'something', good: 'something' }, { bad: 'something', good: 'something' } ];

const retain = objectFields.Retainer(['good']);
retain(array);
console.log(array);
// => [ { good: 'something' }, { good: 'something' } ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>

Disclaimer: I'm the author of object-fields

Comments

0

By reduce:

const newArray = oldArray.reduce((acc, curr) => {
  const { remove_one, remove_two, ...keep_data } = curr;
  acc.push(keep_data);
  return acc;
}, []);

Comments

0

Generic function to remove a property for all objects in an array of objects:

/**
 * Returns the array of objects without the indicated property.
 * @param {array} arrayOfObjects
 * @param {string} property
 * @returns {array}
 * @see https://stackoverflow.com/a/69723902 remove property from an array of objects
 * @see https://github.com/airbnb/javascript#objects--rest-spread new object with certain properties omitted
 */
const removePropertyFromArrayOfObjects = (arrayOfObjects, property) => {
    return arrayOfObjects.reduce((accumulator, currentValue) => {
        const {[property]: _new_name_, ...keep_data} = currentValue;
        accumulator.push(keep_data);
        return accumulator;
    }, []);
};


// Example of use:

const array = [{"bad": "something", "good": "something"}, {"bad": "something", "good": "something"}];

console.log(removePropertyFromArrayOfObjects(array, "bad"));

// Expected output: Array [Object { good: "something" }, Object { good: "something" }]

Comments

-5

var array = [{"bad": "something", "good":"something"},{"bad":"something", "good":"something"}];
var results = array.map(function(item){
  return {good : item["good"]}
});
console.log(JSON.stringify(results));

5 Comments

Could you explain your solution?
Map is a new data structure in JavaScript ES6. Attached link might help you. hackernoon.com/what-you-should-know-about-es6-maps-dc66af6b9a1e
this solution isn't good if you have many props in your items.
Yes! Tried to provide a different approach.
In your comment, you're confusing Map, the data structure which you're not using, with Array.prototype.map, the array method, which you're using.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.