239

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?

Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
Zack Argyle
  • 8,057
  • 4
  • 29
  • 37
  • 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 – Brian Aug 08 '13 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`? – Bergi Aug 08 '13 at 18:43
  • 1
    @Bergi I wonder if they were referring to prototypeJS, or the `Array` prototype, which dystroy exemplified – Ian Aug 08 '13 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. – Denys Séguret Aug 08 '13 at 18:46
  • @dystroy Other than creating another local variable, what's the "pain"? – Ian Aug 08 '13 at 18:47
  • @ian more code to read. About prototype, it might be the each function. – Denys Séguret Aug 08 '13 at 18:48
  • The idea was to find a faster way, storing the length is generally faster. Unfortunately looks like O(n) is the only way to do this. Lame. – Zack Argyle Aug 08 '13 at 18:54
  • 1
    @ZackArgyle Yes, in the general case there's nothing faster. – Denys Séguret Aug 08 '13 at 18:55

18 Answers18

422

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

const newArray = array.map(({dropAttr1, dropAttr2, ...keepAttrs}) => keepAttrs)
piotr_cz
  • 8,755
  • 2
  • 30
  • 25
183

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.
Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • 1
    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 Aug 08 '13 at 18:43
  • 1
    @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). – Denys Séguret Aug 08 '13 at 18:44
  • 1
    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 Aug 08 '13 at 18:49
  • 1
    @Esailija I agree. That's why I precised it was "cosmetic". Isn't it clear in my answer ? – Denys Séguret Aug 08 '13 at 18:50
  • 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. – Zack Argyle Aug 08 '13 at 18:55
  • Yes, the for loop is faster. But really, you don't need to cache the array's length, the engine does a better job than you at this kind of optimizations. – Denys Séguret Aug 08 '13 at 18:56
  • Yeah I guess I'm just used to other programming languages that make a big performance increase. – Zack Argyle Aug 08 '13 at 19:02
  • `array.forEach(v => delete v.bad);` – Anthony Awuley Aug 29 '19 at 21:54
  • not recommended, please see @piotr_cz https://stackoverflow.com/a/46839399/5452834 answered for the latest approach. – Fai Zal Dong Oct 22 '19 at 06:31
  • @FaiZalDong using `delete` should indeed be avoided but that other answer isn't an answer. It doesn't remove the properties but create a new object. I'll add a precision though for the cases such an approach is possible. – Denys Séguret Oct 22 '19 at 06:46
  • this is probably outdated now, is not working – Chris G Sep 30 '22 at 12:13
34

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; 
});
ex0b1t
  • 1,292
  • 1
  • 17
  • 25
23

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

data.map((datum) => {
  return {
    'id':datum.id,
    'title':datum.login
  }
});
NeNaD
  • 18,172
  • 8
  • 47
  • 89
Maifee Ul Asad
  • 3,992
  • 6
  • 38
  • 86
  • 1
    This was exactly what I needed! My objects had about 15 properties and I needed to keep 3. – RCW Jun 16 '22 at 19:13
17

If you use underscore.js:

var strippedRows = _.map(rows, function (row) {
    return _.omit(row, ['bad', 'anotherbad']);
});
Cody
  • 2,467
  • 2
  • 21
  • 30
17
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'}]
akshay_sushir
  • 1,483
  • 11
  • 9
10

For my opinion this is the simplest variant

array.map(({good}) => ({good}))
maplemap
  • 111
  • 1
  • 3
  • 14
    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. – adrien Feb 02 '19 at 13:53
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;
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
8

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

const cleanArray = array.map(item=>{
  delete item.bad
  return item
})
console.log(cleanArray)
Sylvain
  • 509
  • 1
  • 7
  • 17
3

The shortest way in ES6:

array.forEach(e => {delete e.someKey});
Idan
  • 3,604
  • 1
  • 28
  • 33
2

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)

James Marks
  • 341
  • 2
  • 6
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);
Ankit Agarwal
  • 30,378
  • 5
  • 37
  • 62
1

ES6:

const newArray = array.map(({keepAttr1, keepAttr2}) => ({keepAttr1, newPropName: keepAttr2}))
Kanan Farzali
  • 991
  • 13
  • 23
1

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
})
}
Maifee Ul Asad
  • 3,992
  • 6
  • 38
  • 86
Maicon Gilton
  • 581
  • 1
  • 7
  • 6
0

By reduce:

const newArray = oldArray.reduce((acc, curr) => {
  const { remove_one, remove_two, ...keep_data } = curr;
  acc.push(keep_data);
  return acc;
}, []);
Mahdi Ta'ala
  • 360
  • 1
  • 5
  • 16
0

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'])
})
Benson
  • 4,181
  • 2
  • 26
  • 44
Anupam Maurya
  • 1,927
  • 22
  • 26
-1

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/object-fields@2.0.19"></script>

Disclaimer: I'm the author of object-fields

vincent
  • 1,953
  • 3
  • 18
  • 24
-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));
hk_y
  • 1