replace array of object with another array of object base on property - javascript

How to replace array of object with another array of object base on property?
var arr = [
{'status':'ok'},
{'status':'ok'},
{'status':'error'}
]
var arr2 = [
{'status':error, 'msg': 'etc', 'more property':true}
]
arr = arr.forEach((obj,i) => { if(obj.status === 'error'){obj = arr2[i]} return obj })
My above code failed, status ok is gone, I wonder what is wrong.

You can do it using Array#map() to create a new array and Array#find() to find the object in the second array
let arr=[{status:"ok"},{status:"ok"},{status:"error"}],
arr2=[{status:"error",msg:"etc","more property":!0}];
arr = arr.map(a=>{
let fullObj = arr2.find(a2=>a2.status===a.status);
return fullObj ? fullObj : a;
});
console.log(arr);

You could use Object.assign for assigning new properties to a given object.
var arr = [{ status: 'ok' }, { status: 'ok' }, { status: 'error' }],
arr2 = [{ status: 'error', msg: 'etc', 'more property': true }];
arr.forEach(obj => {
if (obj.status === 'error') {
Object.assign(obj, arr2[0]);
}
});
console.log(arr);
.as-console-wrapper { max-height: 100% !important; top: 0; }

var arr = [
{'status':'ok'},
{'status':'ok'},
{'status':'error'}
]
var arr2 = [
{'status':error, 'msg': 'etc', 'more property':true}
]
arr = arr.forEach(obj => { if(obj.status === 'error'){obj = arr2[i]} return obj })
The callback in forEach() can take an additional arg for the index, but you forgot to provide it. So if you're trying to access the index you can do that.
Also, you're assigning arr to the output of forEach, but forEach() does not return anything, it just executes a callback for every element in the array. What you can do is swap it out for map, which is similar, but actually returns a new array.
Ex:
arr = arr.map((obj, i) => obj.status === 'error' ? arr2[i] : obj)

I think what you're trying to do is replace the one with status "error" to be the arr2 object [0] so..
for(obj in arr){
arr[obj] = arr[obj]['status'] == 'error' ? arr2[0] : arr[obj];
}

Related

Modify JavaScript code to use higher order functions

My below code is working fine and gives the correct desired output. But I am trying to use map, filter etc. instead of for loop. Lodash map and filter also works.
var arr = [
{"comp_id":1, desc: 'from comp1', updated: true},
{
"comp_id":2, desc: 'from comp2', updated: false}
];
var complaint_sources = [
{"comp_id":2,"consumer_source":"Hotline In","description_option":"English"},
{"comp_id":1,"consumer_source":"Online","description_option":"Other"},
{"comp_id":1,"consumer_source":"Email","description_option":null},
{"comp_id":2,"consumer_source":"Email","description_option":null}]
for(let i =0 ;i<arr.length;i++) {
let x=[];
for(let j=0;j<complaint_sources.length;j++){
if(arr[i].comp_id === complaint_sources[j].comp_id){
x.push(complaint_sources[j]);
arr[i].comp_src = x;
}
}
}
console.log(arr);
Basically I am looping through arr array and inside that looping through the complaint_sources array and when the comp_id matches I am modifying the arr array and adding a comp_src property to the object of arr array. This comp_src property will be an array of complaint_sources matched by comp_id.
this will work:
var arr = [
{"comp_id":1, desc: 'from comp1', updated: true},
{"comp_id":2, desc: 'from comp2', updated: false}
];
var complaint_sources = [
{"comp_id":2,"consumer_source":"Hotline In","description_option":"English"},
{"comp_id":1,"consumer_source":"Online","description_option":"Other"},
{"comp_id":1,"consumer_source":"Email","description_option":null},
{"comp_id":2,"consumer_source":"Email","description_option":null}
];
const grouped_sources = complaint_sources.reduce((acc, value) => {
(acc[value.comp_id] = acc[value.comp_id] || []).push(value);
return acc;
}, {})
const data = arr.map((comp) => ({
...comp,
comp_src: grouped_sources[comp.comp_id]
}));
console.log(data);

Get paths to nested value

I figured this must be a dup, but I can't find it on SO. Given an object like this:
let obj = { keyA: { keyB: 'hi', keyC: { keyD: null } }, keyE: 'hi' }
Is there a way I can find key paths to a given value, like this:
keyPaths(obj, 'hi') // -> [ 'keyA.keyB', 'keyE' ]
keyPaths(obj) // -> [ 'keyA.keyB.keyD' ]
I tried to adapt some of the answers that find deep values knowing the key, and I was almost able to adapt this one that finds deep nulls, but I can't figure out how to get the path back, instead of just the deepest key.
I would go with a depth first search like this :
let obj = { keyA: { keyB: 'hi', keyC: { keyD: null } }, keyE: 'hi' }
function keyPaths(parent, value = null, chain) {
let allResults = [];
for (const prop in parent) {
if (parent.hasOwnProperty(prop)) {
const element = parent[prop];
const newChain = chain ? chain + '.' + prop : prop;
if (element === value) {
allResults.push(newChain);
}
else if (Object.keys(prop).length > 1) {
allResults = [...allResults, ...keyPaths(element, value, newChain)];
}
}
}
return allResults;
}
console.log(keyPaths(obj, 'hi')) // -> [ 'keyA.keyB', 'keyE' ]
console.log(keyPaths(obj)) // -> [ 'keyA.keyB.keyC' ]
Basically, I check all the properties of the given element for a matching value. If a property doesn't match the value, but has child properties, I recursively call the function, and merge the results from the call iteration and the recursive call.
You do this pretty cleanly by using reduce inside a recursive function. The function will return an array, which you can than map() to whatever string values you want.
let obj = { keyA: { keyB: 'hi', keyC: { keyD: null } }, keyE: 'hi' }
function keyPaths(obj, val, path = [] ){
if (!obj) return
return Object.entries(obj).reduce((res, [k, v]) => {
let p = [...path, k]
if (v == val) res.push(p)
else if (v && typeof v == 'object') res.push(...keyPaths(v, val, p))
return res
}, [])
}
console.log(keyPaths(obj, 'hi').map(a => a.join('.')))
console.log(keyPaths(obj).map(a => a.join('|')))
If it's ok to use Lodash+Deepdash, then:
let paths = _(obj).filterDeep((v)=>v=='hi').paths().value();
Codepen is here

Get array of keys based on values from another array

Say I have an array of objects that looks like this
let myArray = [
{item1: true},
{item2: false},
{item3: true},
{item4: false}
]
How would I iterate though this to return a new array of true values that looks like this:
let newArray = ['item1', 'item3']
I found this function but it only returns single items:
function findKey(map, term) {
var found = [];
for(var property in map) {
if(map.hasOwnProperty(property)) {
for(var key in map[property]) {
if(map[property].hasOwnProperty(key) && key === term) {
found.push(property);
}
}
}
}
return found;
}
Assuming myArray always contains objects with only 1 property.
let newArray = myArray
.map(item => Object.entries(item)[0])
.filter(([key, value]) => value)
.map(([key, value]) => key)
You could access the first key of each array item via Object.keys(), and use this to filter items with a true value for that first key, and then complete the process with a call to map() to transform the item to a value based on the same "first key" technique:
let myArray = [
{item1: true},
{item2: false},
{item3: true},
{item4: false}
]
let result = myArray
.filter(item => item[ Object.keys(item)[0] ] === true)
.map(item => Object.keys(item)[0])
console.log(result)
Use the function reduce to build the desired output. The handler of the function reduce will get the keys and check for each value === true.
This approach checks for the whole set of keys within an object. Further, this way you only use one loop.
let myArray = [{item1: true},{item2: false},{item3: true},{item4: false}],
result = myArray.reduce((a, c) => a.concat(Object.keys(c).filter(k => c[k] === true)), []);
console.log(result);
Something much optimized than the accepted answer would look like this:
const arr = [
{ item1: true },
{ item2: false },
{ item3: true },
{ item4: false }
]
const result = [];
const len = arr.length;
for (let i = 0; i < len; ++i) {
const obj = arr[i];
const key = Object.keys(obj)[0];
if(obj[key]) {
result.push(key);
}
}
console.log(result);
There is only one loop over the array, instead of map and filter which ends up looping twice.
Shortest
let newArray = myArray.map( x=>Object.keys(x)[0] ).filter( (k,i)=>myArray[i][k] );
In above solution first we use: map which works as for-loop to get array of keys (using Object.keys) ["item1", "item2", "item3", "item4"]. Then we filter that array by choose only those keys for which original array object has true. e.g myArray[0]["item1"] -> true (we use fact that filter funtion takes array element (k) and its index (i) which is the same for elements in myArray). In map and filter we use arrow functions.

Push in an a new array and filtering redundant objects in javascript

I receive from an ajax call an array of object and some of them are the same, so i want want to push only unique objects in an another array.
receivedArray = [{name:italy, id:67},{name:italy, id:67},{name:france, id:89}]
and i want that :
myArray = [{name:italy, id:67},{name:france, id:89}]
how can i do that ?
Use reduce & findIndex method. findIndex will return the index of the object if the accumulator array already have an object where the id matches. If index is -1 which mean that accumulator array does not have that object.In that case add the array to the accumulator array
let receivedArray = [{
name: 'italy',
id: 67
}, {
name: 'italy',
id: 67
}, {
name: 'france',
id: 89
}]
let myArray = receivedArray.reduce(function(acc, curr) {
let findIndex = acc.findIndex(function(item) {
return item.id === curr.id;
})
if (findIndex === -1) {
acc.push(curr)
}
return acc;
}, [])
console.log(myArray)
You can use filter and Set to do something like this perhaps:
receivedArray = [{name:'italy', id:67},{name:'italy', id:67},{name:'france', id:89}]
mySet = new Set();
myArray = receivedArray.filter(e => {
if (mySet.has(e['id'])) {
return false;
} else {
mySet.add(e['id']);
return true;
}
})
console.log(myArray);
This can be easily solved in es6:
const receivedArray = [{name:'italy', id:67},{name:'italy', id:67},{name:'france', id:89}]
const newArr = receivedArray.filter((item, index, self) =>
index === self.findIndex((i) => (
i.id === item.id && i.name === item.name
))
)
console.log(newArr)

Pick the array by property name from another array

I have an array like that
I want to pick the array item by property name, I am using lodash for that:
const result = _.map(this.thing, _.property('groups')).filter(x => x !== undefined);
But I am getting array of arrays as result
What I need is just single selected property array.
Any idea how to achieve that?
Try this>>>
var a = [{"p1":[3,4]},{"p2":[6,7]}];
function getArr(arr,key){
var res = [];
for(var v of arr){
if(v[key]!=undefined){
res = v[key];break;
}
};
return res;
}
console.log(getArr(a,"p1"));
If you can use ES6/ES7, you can rely on Object.keys and Object.values to access to the key (that is the property name) and the value (the array you want to get):
var arr = [
{ groups: [1, 2 ] },
{ category: [1, 2, 3 ] },
{ subCategory: [1, 2, 3, 4 ] }
];
function pickArray(propertyName) {
var element = arr.find(el => Object.keys(el)[0] === propertyName)
return element ? Object.values(element)[0] : null;
}
var res = pickArray('category');
console.log(res);
const output
= (Array.from(arr, (obj) => obj['product'], 'product')
.filter(x => typeof x !== 'undefined'))[0];
Try this:
const arr = [ {'groups': ['item1','item2']},
{'categories':['x','y']}
]
var ouptut= arr.find(item=> {
return item[Object.keys(item).find(key=>key === 'groups')]
})
console.log(ouptut)

Categories