Related
compare array of object with array of keys, filter array of object with array keys.
Input:
let a = ['aa'];
let b = [{ aa: 1, bb: 2, c: 30 },{ aa: 2, bb: 3, c: 40}];
output:
b = [{bb: 2, c: 30 },{bb: 3, c: 40}];
original array should be mutate.
Much similiar to #SachilaRanawaka 's answer, but works without modifying the original b array:
let a = ['aa'];
let b = [{ aa: 1, bb: 2, c: 30 },{ aa: 2, bb: 3, c: 40}];
function removeKey(obj, key) {
let clone = Object.assign({}, obj); // <-- shallow clone
if (key in clone) {
delete clone[key];
}
return clone;
}
function removeKeys(keys, objs) {
return objs.map(o => keys.reduce(removeKey, o));
}
console.log(removeKeys(a, b));
You could take a destructuring with getting the rest approach.
This approach does not mutate the original data.
const
unwanted = ['aa'],
data = [{ aa: 1, bb: 2, c: 30 }, { aa: 2, bb: 3, c: 40 }],
result = data.map(o => unwanted.reduce((q, k) => {
const { [k]: _, ...r } = q;
return r;
}, o));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can simply achieve this requirement with the help of Array.forEach() method.
Live Demo :
let a = ['aa'];
let b = [{ aa: 1, bb: 2, c: 30 },{ aa: 2, bb: 3, c: 40}];
b.forEach(obj => {
Object.keys(obj).forEach(key => {
a.forEach(item => delete obj[item])
});
});
console.log(b);
It can probably be solved with less lines of code, but this was the first i could think of.
let keysToRemove = ['aa'];
let array = [{ aa: 1, bb: 2, c: 30 },{ aa: 2, bb: 3, c: 40}];
let result = array.map((item) => {
let filtered = Object.keys(item)
.filter((key) => !keysToRemove.includes(key))
.reduce((obj, key) => {
obj[key] = item[key];
return obj;
}, {});
return filtered;
});
console.log(result);
use the map operator and use delete to delete properties from the object
let a = ['aa'];
let b = [{ aa: 1, bb: 2, c: 30 },{ aa: 2, bb: 3, c: 40}];
const result = b.map(item => {
Object.keys(item).forEach(key => {
if(a.includes(key)){
delete item[key]
}
})
return item
})
console.log(result)
This question already has answers here:
Find object by id in an array of JavaScript objects
(36 answers)
Closed 4 years ago.
Let's say I have an array of four objects:
var jsObjects = [
{a: 1, b: 2},
{a: 3, b: 4},
{a: 5, b: 6},
{a: 7, b: 8}
];
Is there a way that I can get the third object ({a: 5, b: 6}) by the value of the property b for example without a for...in loop?
Filter array of objects, which property matches value, returns array:
var result = jsObjects.filter(obj => {
return obj.b === 6
})
See the MDN Docs on Array.prototype.filter()
const jsObjects = [
{a: 1, b: 2},
{a: 3, b: 4},
{a: 5, b: 6},
{a: 7, b: 8}
]
let result = jsObjects.filter(obj => {
return obj.b === 6
})
console.log(result)
Find the value of the first element/object in the array, otherwise undefined is returned.
var result = jsObjects.find(obj => {
return obj.b === 6
})
See the MDN Docs on Array.prototype.find()
const jsObjects = [
{a: 1, b: 2},
{a: 3, b: 4},
{a: 5, b: 6},
{a: 7, b: 8}
]
let result = jsObjects.find(obj => {
return obj.b === 6
})
console.log(result)
jsObjects.find(x => x.b === 6)
From MDN:
The find() method returns a value in the array, if an element in the array satisfies the provided testing function. Otherwise undefined is returned.
Side note: methods like find() and arrow functions are not supported by older browsers (like IE), so if you want to support these browsers, you should transpile your code using Babel.
I don't know why you are against a for loop (presumably you meant a for loop, not specifically for..in), they are fast and easy to read. Anyhow, here's some options.
For loop:
function getByValue(arr, value) {
for (var i=0, iLen=arr.length; i<iLen; i++) {
if (arr[i].b == value) return arr[i];
}
}
.filter
function getByValue2(arr, value) {
var result = arr.filter(function(o){return o.b == value;} );
return result? result[0] : null; // or undefined
}
.forEach
function getByValue3(arr, value) {
var result = [];
arr.forEach(function(o){if (o.b == value) result.push(o);} );
return result? result[0] : null; // or undefined
}
If, on the other hand you really did mean for..in and want to find an object with any property with a value of 6, then you must use for..in unless you pass the names to check.
Example
function getByValue4(arr, value) {
var o;
for (var i=0, iLen=arr.length; i<iLen; i++) {
o = arr[i];
for (var p in o) {
if (o.hasOwnProperty(p) && o[p] == value) {
return o;
}
}
}
}
Ways to achieve the requirement :
Using Array.find() method :
const jsObject = [
{a: 1, b: 2},
{a: 3, b: 4},
{a: 5, b: 6},
{a: 7, b: 8}
];
const filteredResult = jsObject.find((e) => e.b == 6);
console.log(filteredResult);
Using Array.filter() method :
const jsObjects = [
{a: 1, b: 2},
{a: 3, b: 4},
{a: 5, b: 6},
{a: 7, b: 8}
];
const filterObj = jsObjects.filter((e) => e.b == 6);
console.log(filterObj[0]);
Using for...in loop :
const jsObjects = [
{a: 1, b: 2},
{a: 3, b: 4},
{a: 5, b: 6},
{a: 7, b: 8}
];
for (const i in jsObjects) {
if (jsObjects[i].b == 6) {
console.log(jsObjects[i]);
}
}
OK, there are few ways to do that, but let's start with the simplest one and latest approach to do this, this function is called find().
Just be careful when you using find to as even IE11 dosn't support it, so it needs to be transpiled...
so you have this object as you said:
var jsObjects = [
{a: 1, b: 2},
{a: 3, b: 4},
{a: 5, b: 6},
{a: 7, b: 8}
];
and you can write a function and get it like this:
function filterValue(obj, key, value) {
return obj.find(function(v){ return v[key] === value});
}
and use the function like this:
filterValue(jsObjects, "b", 6); //{a: 5, b: 6}
Also in ES6 for even shortened version:
const filterValue = (obj, key, value)=> obj.find(v => v[key] === value);
This method only return the first value which match..., for better result and browser support, you can use filter:
const filterValue = (obj, key, value)=> obj.filter(v => v[key] === value);
and we will return [{a: 5, b: 6}]...
This method will return an array instead...
You simpley use for loop as well, create a function like this:
function filteredArray(arr, key, value) {
const newArray = [];
for(i=0, l=arr.length; i<l; i++) {
if(arr[i][key] === value) {
newArray.push(arr[i]);
}
}
return newArray;
}
and call it like this:
filteredArray(jsObjects, "b", 6); //[{a: 5, b: 6}]
See this documentation Array.prototype.find()
Example:
var inventory = [
{name: 'apples', quantity: 2},
{name: 'bananas', quantity: 0},
{name: 'cherries', quantity: 5}
];
function findCherries(fruit) {
return fruit.name === 'cherries';
}
console.log(inventory.find(findCherries));
// { name: 'cherries', quantity: 5 }
Using underscore.js:
var foundObject = _.findWhere(jsObjects, {b: 6});
It looks like in the ECMAScript 6 proposal there are the Array methods find() and findIndex(). MDN also offers polyfills which you can include to get the functionality of these across all browsers.
find():
function isPrime(element, index, array) {
var start = 2;
while (start <= Math.sqrt(element)) {
if (element % start++ < 1) return false;
}
return (element > 1);
}
console.log( [4, 6, 8, 12].find(isPrime) ); // undefined, not found
console.log( [4, 5, 8, 12].find(isPrime) ); // 5
findIndex():
function isPrime(element, index, array) {
var start = 2;
while (start <= Math.sqrt(element)) {
if (element % start++ < 1) return false;
}
return (element > 1);
}
console.log( [4, 6, 8, 12].findIndex(isPrime) ); // -1, not found
console.log( [4, 6, 7, 12].findIndex(isPrime) ); // 2
If I understand correctly, you want to find the object in the array whose b property is 6?
var found;
jsObjects.some(function (obj) {
if (obj.b === 6) {
found = obj;
return true;
}
});
Or if you were using underscore:
var found = _.select(jsObjects, function (obj) {
return obj.b === 6;
});
If you are looking for a single result, rather than an array, may I suggest reduce?
Here is a solution in plain 'ole javascript that returns a matching object if one exists, or null if not.
var result = arr.reduce(function(prev, curr) { return (curr.b === 6) ? curr : prev; }, null);
You can use it with the arrow function as well like as below :
var demoArray = [
{name: 'apples', quantity: 2},
{name: 'bananas', quantity: 0},
{name: 'cherries', quantity: 5}
];
var result = demoArray.filter( obj => obj.name === 'apples')[0];
console.log(result);
// {name: 'apples', quantity: 2}
How about using _.find(collection, [predicate=_.identity], [fromIndex=0]) of lo-dash to get object from array of objects by object property value. You could do something like this:
var o = _.find(jsObjects, {'b': 6});
Arguments:
collection (Array|Object): The collection to inspect.
[predicate=_.identity] (Function): The function invoked per iteration.
[fromIndex=0] (number): The index to search from.
Returns
(*): Returns the matched element (in your case, {a: 5, b: 6}), else undefined.
In terms of performance, _.find() is faster as it only pulls the first object with property {'b': 6}, on the other hand, if suppose your array contains multiple objects with matching set of properties (key:value), then you should consider using _.filter() method. So in your case, as your array has a single object with this property, I would use _.find().
Made the best/fastest part of this answer more re-usable & clear:
function getElByPropVal(myArray, prop, val){
for (var i = 0, length = myArray.length; i < length; i++) {
if (myArray[i][prop] == val){
return myArray[i];
}
}
}
var result = jsObjects.filter(x=> x.b === 6);
will be better, using return in filter sometimes you can't get result (I dunno why)
To get first object from array of objects by a specific property value:
function getObjectFromObjectsArrayByPropertyValue(objectsArray, propertyName, propertyValue) {
return objectsArray.find(function (objectsArrayElement) {
return objectsArrayElement[propertyName] == propertyValue;
});
}
function findObject () {
var arrayOfObjectsString = document.getElementById("arrayOfObjects").value,
arrayOfObjects,
propertyName = document.getElementById("propertyName").value,
propertyValue = document.getElementById("propertyValue").value,
preview = document.getElementById("preview"),
searchingObject;
arrayOfObjects = JSON.parse(arrayOfObjectsString);
console.debug(arrayOfObjects);
if(arrayOfObjects && propertyName && propertyValue) {
searchingObject = getObjectFromObjectsArrayByPropertyValue(arrayOfObjects, propertyName, propertyValue);
if(searchingObject) {
preview.innerHTML = JSON.stringify(searchingObject, false, 2);
} else {
preview.innerHTML = "there is no object with property " + propertyName + " = " + propertyValue + " in your array of objects";
}
}
}
pre {
padding: 5px;
border-radius: 4px;
background: #f3f2f2;
}
textarea, button {
width: 100%
}
<fieldset>
<legend>Input Data:</legend>
<label>Put here your array of objects</label>
<textarea rows="7" id="arrayOfObjects">
[
{"a": 1, "b": 2},
{"a": 3, "b": 4},
{"a": 5, "b": 6},
{"a": 7, "b": 8, "c": 157}
]
</textarea>
<hr>
<label>property name: </label> <input type="text" id="propertyName" value="b"/>
<label>property value: </label> <input type="text" id="propertyValue" value=6 />
</fieldset>
<hr>
<button onclick="findObject()">find object in array!</button>
<hr>
<fieldset>
<legend>Searching Result:</legend>
<pre id="preview">click find</pre>
</fieldset>
Using find with bind to pass specific key values to a callback function.
function byValue(o) {
return o.a === this.a && o.b === this.b;
};
var result = jsObjects.find(byValue.bind({ a: 5, b: 6 }));
var jsObjects = [{a: 1, b: 2}, {a: 3, b: 4}, {a: 5, b: 6}, {a: 7, b: 8}];
to access the third object, use: jsObjects[2];
to access the third object b value, use: jsObjects[2].b;
I have an array with objects. I filtered the array and returned the values that correspond with a condition. After that i created a new array what contains data from first. This array contains a value a which should overrides the first array.
const arr = [{
a: 1,
b: 2,
name: 'one'
},
{
a: 1,
b: 7,
name: 'two'
}
]
const b = [1, 2]
const res = arr.filter(i => b.includes(i.b))
const newArr = {
...res,
a: 'newdata'
}
console.log(newArr)
In console i got:
{
"0": {
"a": 1,
"b": 2,
"name": "one"
},
"a": "newdata"
}
But the expected output is:
{
"a": "newdata"
"b": 2,
"name": "one"
},
Why i get this and how to get the expected result?
After you filter the values you're interested in, you could use Array.map(..) to go through all the items and change their a property, here is an example:
const arr = [{
a: 1,
b: 2,
name: 'one'
},
{
a: 1,
b: 7,
name: 'two'
}
]
const b = [1, 2]
const res = arr.filter(i => b.includes(i.b)).map(i => ({...i, a: 'newdata'}));
console.log(res)
You simply spread an array and you get the indices from the array/object as key and the item/object as value.
Instead, you could take a function for a new object with additional key/value and map the filtered result by using the function.
const
arr = [{ a: 1, b: 2, name: 'one' }, { a: 1, b: 7, name: 'two' }],
b = [1, 2, 7],
res = arr.filter(i => b.includes(i.b)),
newObject = o => ({ ...o, a: 'newdata' }),
newArr = res.map(newObject);
console.log(newArr);
I am trying to merge two arrays of objects without using the unionBy method from lodash.
Currently I have the following code working perfectly:
var array1 = [
{ a: 1, b: 'first'},
{ a: 2, b: 'second'}
];
var array2 = [
{ a: 3, b: 'third'},
{ a: 1, b: 'fourth'}
];
var array3 = __.unionBy(array2, array1, 'a');
This outputs:
[
{
"a": 3,
"b": "third"
},
{
"a": 1,
"b": "fourth"
},
{
"a": 2,
"b": "second"
}
]
This is the desired result but I can't use unionBy in my current work environment, so I'm looking for a result that uses either native JS or other lodash methods 3.6.0 or lower.
Concat and use Array#filter with a helper object to remove duplicates:
var array1 = [{"a":1,"b":"first"},{"a":2,"b":"second"}];
var array2 = [{"a":3,"b":"third"},{"a":1,"b":"fourth"}];
var result = array2.concat(array1).filter(function(o) {
return this[o.a] ? false : this[o.a] = true;
}, {});
console.log(result);
If ES6 is an option you can use a Set instead of the helper object:
const array1 = [{"a":1,"b":"first"},{"a":2,"b":"second"}];
const array2 = [{"a":3,"b":"third"},{"a":1,"b":"fourth"}];
const result = array2.concat(array1).filter(function(o) {
return this.has(o.a) ? false : this.add(o.a);
}, new Set());
console.log(result);
If you want to use an arrow function, you can't use the thisArg of Array.filter() to bind the Set as the this of the function (you can't bind this to arrow functions). You can use a closure instead (attribute for the method goes to #NinaScholz).
const array1 = [{"a":1,"b":"first"},{"a":2,"b":"second"}];
const array2 = [{"a":3,"b":"third"},{"a":1,"b":"fourth"}];
const result = [...array2, ...array1]
.filter((set => // store the set and return the actual callback
o => set.has(o.a) ? false : set.add(o.a)
)(new Set()) // use an IIFE to create a Set and store it set
);
console.log(result);
You could take a Set for filtering to get unique values.
var array1 = [{ a: 1, b: 'first' }, { a: 2, b: 'second' }],
array2 = [{ a: 3, b: 'third' }, { a: 1, b: 'fourth' }],
s = new Set,
array3 = array2.map(o => (s.add(o.a), o)).concat(array1.filter(o => !s.has(o.a)));
console.log(array3);
You can use an ES6 Map for this. Construct it with the data, keyed by the a property value, and then take the values out of the Map again:
var array1 = [{"a":1,"b":"first"},{"a":2,"b":"second"}],
array2 = [{"a":3,"b":"third"},{"a":1,"b":"fourth"}];
var result = [...new Map([...array1,...array2].map( o => [o.a, o] )).values()];
console.log(result);
You can merge the 2 arrays and then filter the ones with same property a:
var array1 = [{ a: 1, b: 'first'},{ a: 2, b: 'second'}],
array2 = [{ a: 3, b: 'third'},{ a: 1, b: 'fourth'}],
array3 = [...array2, ...array1].filter((item, pos, arr) =>
arr.findIndex(item2 => item.a == item2.a) == pos);
console.log(array3)
If you want to still be able to specify the property by which to union you can implement you own function like this:
var array1 = [{ a: 1, b: 'first'},{ a: 2, b: 'second'}],
array2 = [{ a: 3, b: 'third'},{ a: 1, b: 'fourth'}],
array3 = unionBy(array1, array2, 'a');
function unionBy(array1, array2, prop){
return [...array2, ...array1].filter((item, pos, arr) =>
arr.findIndex(item2 => item[prop] == item2[prop]) == pos);
}
console.log(array3);
Note: One advantage of my answer over some of the answers is that it preserves the order like in lodash which may or may not be important.
ES5 using Array.filter and Array.find
var array1 = [{ a: 1, b: "first" }, { a: 2, b: "second" }];
var array2 = [{ a: 3, b: "third" }, { a: 1, b: "fourth" }];
function merge(a, b, prop) {
var reduced = a.filter(function(itemA) {
return !b.find(function(itemB) {
return itemA[prop] === itemB[prop];
});
});
return reduced.concat(b);
}
console.log(merge(array1, array2, "a"));
ES6 arrow functions
var array1 = [{ a: 1, b: "first" }, { a: 2, b: "second" }];
var array2 = [{ a: 3, b: "third" }, { a: 1, b: "fourth" }];
function merge(a, b, prop) {
const reduced = a.filter(
itemA => !b.find(itemB => itemA[prop] === itemB[prop])
);
return reduced.concat(b);
}
console.log(merge(array1, array2, "a"));
Another ES6 one line experiment
var array1 = [{ a: 1, b: "first" }, { a: 2, b: "second" }];
var array2 = [{ a: 3, b: "third" }, { a: 1, b: "fourth" }];
const merge = (a, b, p) => a.filter( aa => ! b.find ( bb => aa[p] === bb[p]) ).concat(b);
console.log(merge(array1, array2, "a"));
You could use ES6 find and reduce function smartly!
var array1 = [{"a":1,"b":"first"},{"a":2,"b":"second"}];
var array2 = [{"a":3,"b":"third"},{"a":1,"b":"fourth"}];
var res = array1.concat(array2).reduce((aggr, el)=>{
if(!aggr.find(inst=>inst.a==el.a))
return [...aggr, el];
else
return aggr
},[])
console.log(res);
i'm trying to work with reduce or map, but i'm a noob some times.
i'm trying to use this function to return a single array from the objects.
var obj = [{ a: 1 }, { b: 2 }, { c: 3 }];
var result = obj.reduce((obj, item) => [item.key] = item.value);
console.log(result);
but i'm always getting :
Uncaught TypeError: Cannot read property 'Symbol(Symbol.iterator)'
of undefined
I searched a lot, but the examples didn't help me... i think that's something simple, but after 1 hour, i'm nothing getting .
What i want..
[{a: 1}, {b: 2}, {c: 3}] to {a: 1, b: 2, c: 3}
You could use Object.assign and spread syntax ....
var obj = [{ a: 1 }, { b: 2 }, { c: 3 }];
console.log(Object.assign({}, ...obj));
With Array#reduce
var obj = [{ a: 1 }, { b: 2 }, { c: 3 }];
console.log(obj.reduce((r, o) => Object.assign(r, o), {}));
Without Object.assign
var obj = [{ a: 1 }, { b: 2 }, { c: 3 }];
console.log(obj.reduce((r, o) => (Object.entries(o).forEach(([k, v]) => r[k] = v), r), {}));
ES5
var obj = [{ a: 1 }, { b: 2 }, { c: 3 }];
console.log(obj.reduce(function (r, o) {
Object.keys(o).forEach(function (k) {
r[k] = o[k];
});
return r;
}, {}));
If you want to use reduce:
var arr = [{ a: 1 }, { b: 2 }, { c: 3 }];
var result = arr.reduce((obj, item) => Object.assign(obj, item), {});
Check the MDN documentation when in doubt.
you can do it in the following way using reduce
var obj = [{ a: 1 }, { b: 2 }, { c: 3 }];
var result = obj.reduce((obj, item) => {
Object.assign(obj, item)
return obj;
}, {});
console.log(result);