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)
I stuggle a lot with data I get from an API:
This is the way the data gets returned, the amout of arrays differs.
const objData = {
arr1: [1,2,3],
arr2: [1,2,1],
arr3: [2,1,2],
arr4: ["a","b", "c"]
}
This is the way it SHOULD look
const desired = [
{a: 1, b: 1, c: 2, d: "a"},
{a: 2, b: 2, c: 1, d: "b"},
{a: 2, b: 1, c: 2, d: "c"}
]
This gives me the desired result, but it is not dymanic, since I have to provide the names of the arrays, and the amount of arrays in the object is not allowed to change.
const DataObj = []
for (let i = 0; i < objData.arr1.length; i++) {
const objX = {
a: objData.arr1[i],
b: objData.arr2[i],
c: objData.arr3[i],
d: objData.arr4[i],
}
DataObj.push(objX)
}
Can anybody help me to solve this? How can I make this independent from the names of the arrays and the amount of arrays in the dataset?
You could map the arrays with new objects.
const
objData = { arr1: [1, 2, 3], arr2: [1, 2, 3], arr3: [2, 1, 2], arr4: ["a", "b", "c"] },
keys = { arr1: 'a', arr2: 'b', arr3: 'c', arr4: 'd' },
result = Object
.entries(objData)
.reduce((r, [key, array]) => array.map((v, i) => ({ ...r[i], [keys[key]]: v })), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Non functional approach, use integers to get your letters
const objData = {
arr1: [1, 2, 3, 5],
arr2: [1, 2, 1, 4],
arr3: [2, 1, 2, 3],
arr4: ["a", "b", "c", "d"]
}
const len = Object.values(objData)[0].length;
let cnt = 97;
let newObj = {};
const list = [];
for (let i = 0; i < len; i++) {
for (let key in objData) {
newObj[String.fromCharCode(cnt)] = objData[key][i];
++cnt
}
list.push(newObj);
cnt = 97;
newObj = {};
}
console.log(list)
So I have this data:
fields = ['a', 'b', 'c']
data = [{r: 1, a: 2, b: 3, c: 4, h: 5}, {r: 4, a: 9, b: 1, c: 4, h: 5} ... ]
and I want to be able (preferred with lodash) to be able to get to this:
newData = [{r:1, h:5, values: [{name: 'a', value: 2},{name: 'b', value: 3}, {name: 'c', value: 4}], .....]
Meaning only the fields from the 'fields' object be taken out of each object in array (they always exist) and put into 'values' property that has an array of them in the format displayed here.
Would love to hear suggestions of the cleanest way to achieve this!
I did this :
function something(data, fields) {
const formattedData = _.map(data, (currData) => {
const otherFields = _.omit(currData, fields)
return {
...otherFields,
values: _.flow(
currData => _.pick(currData, fields),
pickedFields => _.toPairs(pickedFields),
pairs => _.map(pairs, pair => {
return { name: pair[0], value: pair[1] }
})
)(currData)
}
})
return formattedData
}
which works, but I'm wondering if it isn't a bit complicated.
The _.flow() method creates a function, which you can extract and name. In addition, the 1st function in the flow, accepts more than 1 parameter, so you don't need to pass it explicitly. Since _.toPairs() is unary, you don't need to wrap it in an arrow function.
The object creation is a bit annoying. I've used _.zipObject(), but it's still cumbersome.
Now you can use the function create by _.flow() in your main function, and it's pretty readable:
const { flow, pick, toPairs, map, partial, zipObject, omit } = _
const propsToObjs = flow(
pick,
toPairs,
pairs => map(pairs, partial(zipObject, ['name', 'value'])),
)
const fn = (data, fields) =>
map(data, currData => ({
...omit(currData, fields),
values: propsToObjs(currData, fields)
}))
const fields = ['a', 'b', 'c']
const data = [{r: 1, a: 2, b: 3, c: 4, h: 5}, {r: 4, a: 9, b: 1, c: 4, h: 5}]
const result = fn(data, fields)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
Using lodash/fp, we can make the flow function even nicer, since lodash/fp functions are auto-curried and iteratee-first data-last (not the reversed order of parameters):
const { flow, pick, toPairs, map, partial, zipObject, omit } = _
const propsToObjs = flow(
pick,
toPairs,
map(zipObject(['name', 'value']))
)
const fn = fields => map(currData => ({
...omit(fields, currData),
values: propsToObjs(fields, currData)
}))
const fields = ['a', 'b', 'c']
const data = [{r: 1, a: 2, b: 3, c: 4, h: 5}, {r: 4, a: 9, b: 1, c: 4, h: 5}]
const result = fn(fields)(data)
console.log(result)
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>
You could map through the objects in data and then check if the key is in the fields array:
fields = ["a", "b", "c"];
data = [
{ r: 1, a: 2, b: 3, c: 4, h: 5 },
{ r: 4, a: 9, b: 1, c: 4, h: 5 },
];
let newData = data.map((o) => {
let newObject = {};
newObject.values = [];
for (let k in o) {
if (fields.includes(k)) {
newObject.values.push({
name: k,
value: o[k]
});
} else {
newObject[k] = o[k];
}
}
return newObject;
});
console.log(newData);
You could destructure the object, pick the wanted properties and return the rest of the object with wanted values.
const
fields = ['a', 'b', 'c'],
data = [{ r: 1, a: 2, b: 3, c: 4, h: 5 }, { r: 4, a: 9, b: 1, c: 4, h: 5 }],
result = data.map(o => {
const values = fields.map(name => {
let value;
({ [name]: value, ...o } = o);
return { name, value };
});
return { ...o, values };
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
let a = [{
a:1,
b:3,
c:[1, 2, 6]
},
{
a:3,
b:10,
c:[2, 5, 4]
},
{
a:4,
b:3,
c:[7, 12, 6]
},
{
a:4,
b:12,
}]
let b = [2, 6]
I want to return an array from a object that matches from b arrays.
I used :
lodash.forEach(b , (value)=>{
lodash.filter(a, {c: value})
}
but this doesnt work . I tried to simple my code for better underestanding.
You could filter the array by looking if the values of b are included in c.
var a = [{ a: 1, b: 3, c: [1, 2, 6] }, { a: 3, b: 10, c: [2, 5, 4] }, { a: 4, b: 3, c: [7, 12, 6] }, { a: 4, b: 12 }],
b = [2, 6],
result = a.filter(({ c = [] }) => b.some(v => c.includes(v)));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
For getting only items who match completely, you could use Array#every instead of Array#some.
var a = [{ a: 1, b: 3, c: [1, 2, 6] }, { a: 3, b: 10, c: [2, 5, 4] }, { a: 4, b: 3, c: [7, 12, 6] }, { a: 4, b: 12 }],
b = [2, 6],
result = a.filter(({ c = [] }) => b.every(v => c.includes(v)));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
To find objects with c contain all b values you can use Array.filter() and Array.every():
let a = [{ a: 1, b: 3, c: [1, 2, 6] }, { a: 3, b: 10, c: [2, 5, 4] }, { a: 4, b: 3, c: [7, 12, 6] }, { a: 4, b: 12 }];
let b = [2, 6]
console.log(a.filter(({c = []}) => b.every(v => c.includes(v))));
if you want common values use Array.some() instead of Array.every():
let a = [{ a: 1, b: 3, c: [1, 2, 6] }, { a: 3, b: 10, c: [2, 5, 4] }, { a: 4, b: 3, c: [7, 12, 6] }, { a: 4, b: 12 }];
let b = [2, 6]
console.log(a.filter(({c = []}) => b.some(v => c.includes(v))));
I believe this is what you want - you can do it in pure JS:
let a = [{
a:1,
b:3,
c:[1, 2, 6]
},
{
a:3,
b:10,
c:[2, 5, 4]
},
{
a:4,
b:3,
c:[7, 12, 6]
},
{
a:4,
b:12,
}]
let b = [2, 6]
let c = a.filter(({ c = [] }) => c ? b.some(n => c.includes(n))) : false;
console.log(c);
Assuming you want to filter objects in array a that have atleast one value in c which exists in b array.
You can use Array.filter, Array.some & Array.includes
let a=[{a:1,b:3,c:[1,2,6]},{a:3,b:10,c:[2,5,4]},{a:4,b:3,c:[7,12,6]},{a:4,b:12,}];
let b=[2,6];
let result = a.filter(v => v.c && v.c.some(v1 => b.includes(v1)));
console.log(result);
You can use lodash as follows
let a=[{a:1,b:3,c:[1,2,6]},{a:3,b:10,c:[2,5,4]},{a:4,b:3,c:[7,12,6]},{a:4,b:12,}];
let b=[2,6];
let result = _.filter(a, v => v.c && _.some(v.c, c => _.includes(b,c)));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
given this array var array = [{a:1, b: 2, c: 3}, {a: 2, b: 4, c: 4}].
I want to iterate through each item in the array and omit the key c and it's value using lodash.
here is the method I tried
_.each(array, function (obj) {
return _.omit(obj, ['a']);
});
Expected Output should be // [{b: 2, c: 3}, {b: 4, c: 4} ]
but lodash returns the original array// [{a:1, b: 2, c: 3}, {a: 2, b: 4, c: 4}]
Instead of forEach() to return new modified array you should use map(), also first parameter is array.
var array = [{a:1, b: 2, c: 3}, {a: 2, b: 4, c: 4}]
var result = _.map(array, function (obj) {
return _.omit(obj, ['a']);
});
console.log(JSON.stringify(result, 0, 4))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
A probably-not-the-lo-dash-iest way of handling it (assuming you actually want to omit a):
_.each(lnkn, function (obj) {
var returnObj = {};
for (prop in obj) {
if (obj.hasOwnProperty(prop) {
if (prop !== 'a') {
returnObj[prop] = obj[prop];
}
}
}
return returnObj;
});
_.forEach is supposed to return the original array. You re looking for _.map.
const array = [{a:1, b: 2, c: 3}, {a: 2, b: 4, c: 4}];
const result = _.map(array, obj => _.omit(obj, 'a'));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
Or you can modify the objects in place:
const array = [{a:1, b: 2, c: 3}, {a: 2, b: 4, c: 4}];
_.forEach(array, obj => {
delete obj.a;
});
console.log(array);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>