If I have an array of objects and one object in JavaScript:
var data = [{"a": 1, "b": 2}, {"a": 1}, {"a": 1, "b": 2, "c": 3}];
var myFilter = {"a": 1, "b": 2};
...and would like to use myFilter object as a filter to the array of objects to create a new array of objects if and only if the object at least matches or contain the myFilter key/value pairs.
Any recommendation how can I go ahead and put it into code? I need to create a new array that was filtered from data using the myFilter key/value pair.
I was able to do this but myFilter only contains 1 key/value pair.
My expected new array is:
var newArr = [];
newArr = [{"a": 1, "b": 2}, {"a": 1, "b": 2, "c": 3}];
You can use arr.filter(callback[, thisArg]) for this:
var data = [{ "a": 1, "b": 2 }, { "a": 1 }, { "a": 1, "b": 2, "c": 3 }]
var myFilter = { "a": 1, "b": 2 }
var myFilterFunction = function(obj) {
for (var p in myFilter) {
if (obj[p] !== myFilter[p]) return false
}
return true
}
var newArr = data.filter(myFilterFunction)
document.write(JSON.stringify(newArr))
A more universal approach would be this filterFuncByObj(filterObj) function, wich takes any custom filter object:
data.filter(filterFuncByObj(myFilter)):
var data = [{ "a": 1, "b": 2 }, { "a": 1 }, { "a": 1, "b": 2, "c": 3 }]
var myFilter = { "a": 1, "b": 2 }
var newArr = data.filter(filterFuncByObj(myFilter))
// Demo Output
document.write(JSON.stringify(newArr))
function filterFuncByObj(filterObj) {
return function(obj) {
for (var p in filterObj) {
if (obj[p] !== filterObj[p]) return false
}
return true
}
}
Using Array.filter(), Object.keys() and Array.every() this could be one way to go
var data = [{"a": 1, "b": 2}, {"a": 1}, {"a": 1, "b": 2, "c": 3}];
var myFilter = {"a": 1, "b": 2};
var filteredData = data.filter(function(d) {
return Object.keys(myFilter).every(function(f) {
return d[f] === myFilter[f];
})
});
console.log(JSON.stringify(filteredData));
The lodash way, just in case:
var data = [{ "a": 1, "b": 2 }, { "a": 1 }, { "a": 1, "b": 2, "c": 3 }];
var myFilter = { "a": 1, "b": 2 };
var newArr = _.filter(data, myFilter);
document.write(JSON.stringify(newArr, null, 3));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
Related
Example:
["a", "b"] -> 1
["c", "d", "e"] -> 2
I want to be able to give "d" as key and get 2.
This work with your example, but I am not sure it covers your real life case :D
const arrays = [['a','b'],['c','d','e']]
const struct = arrays.reduce((acc, array, index) => {
array.forEach(v => acc[v] = index + 1)
return acc
}, {})
console.log(struct)
console.log(struct.d)
output
{a: 1, b: 1, c: 2, d: 2, e: 2}
2
You could just use an object like this:
{
"a": 1,
"b": 1,
"c": 2,
"d": 2,
"e": 2,
}
but this has the problem of if you wanted to change all 1s to 3, you'd have to change it in each place.
You can do this:
const data = [1, 2];
const map = {
"a": data[0],
"b": data[0],
"c": data[1],
"d": data[1],
"e": data[1],
}
so that you only have to set the result in one place.
you can also do stuff with Sets or nested arrays, but that prevents the lookup from being O(1) and changes it to O(n) or O(n*m) based on implementation.
Not sure if exactly what you are looking for but you can do it with built-in object and array methods.
Object.fromEntries(
Object.entries(["c", "d", "e"]).map((a) => {
a.reverse();
a[1] = Number(a[1]);
return a;
})
);
This will output:
{ c: 0, d: 1, e: 2 }
But I see you want to start from 1 and not 0, in that case you could map bit more:
Object.fromEntries(
Object.entries(["c", "d", "e"]).map((a) => {
a.reverse();
a[1] = Number(a[1]) + 1;
return a;
})
);
Then you get
{ c: 1, d: 2, e: 3 }
I am stuck in a situation.
I have an array
arr: [
{
"a": "1"
},
{
"b": "4"
},
{
"c": "6"
},
{
"d": "9"
}
]
and an array
[a,c]
I want my output an array which have only a and c as per array. Can someone please suggest.
Output desired
arr: [
{
"a": "1"
},
{
"c": "6"
}
]
You have to apply a filter to arr1 and check if the key of arr1 is there in arr2 like:
let arr1 = [
{
a: '1'
},
{
b: '4'
},
{
c: '6'
},
{
d: '9'
}
];
let arr2 = ['a', 'c'];
let result = arr1.filter(item => arr2.includes(Object.keys(item)[0]));
alert(JSON.stringify(result));
I think you have to do something like this
let arr1 = [
{
"a": "1"
},
{
"b": "4"
},
{
"c": "6"
},
{
"d": "9"
}
];
let arr2 = ["a","c"];
let result = []
for(let obj of arr1){
for(let key of arr2){
if(obj.hasOwnProperty(key)){
result.push(obj);
break;
}
}
}
alert(JSON.stringify(result));
I've this object:
const dataset = {
"2019": {
"a": 1,
"b": 2,
"c": 3,
"d": 4
},
"2020": {
"a": 2,
"b": 4,
"c": 6,
"d": 8
},
"2021": {
"a": 10,
"b": 11,
"c": 12,
"d": 13
}
}
I would like to obtain these two objects:
const obj1 = {
"2019": {
"a": 1,
"c": 3,
},
"2020": {
"a": 2,
"c": 6,
},
"2021": {
"a": 10,
"c": 12,
}
}
const obj2 = {
"2019": {
"b": 2,
"d": 4
},
"2020": {
"b": 4,
"d": 8
},
"2021": {
"b": 11,
"d": 13
}
}
So "split" the object in two objects based on some keys of the inner objects.
Here is what I tried:
function pickKeys(dataObj, keys) {
return Object.entries(dataObj).map(([d, obj]) => {
return { [d]: _.pick(obj, keys) }
})
}
const obj1 = pickKeys(dataset, ['a', 'c'])
The result is:
const obj1 = [
{ '2019': { a: 1, c: 3 } },
{ '2020': { a: 2, c: 6 } },
{ '2021': { a: 10, c: 12 } }
]
So almost there but it's not perfect. Which is the better way to do that?
You do this using combination of map, reduce methods and one for...in loop that will turn array of keys into array of objects. Then you can use array destructuring to get two separate objects.
const dataset = {"2019":{"a":1,"b":2,"c":3,"d":4},"2020":{"a":2,"b":4,"c":6,"d":8},"2021":{"a":10,"b":11,"c":12,"d":13}}
const [a, b] = [['a', 'c'], ['b', 'd']]
.map(keys => keys.reduce((r, key) => {
for (let year in dataset) {
if (!r[year]) r[year] = {}
r[year][key] = dataset[year][key]
}
return r;
}, {}))
console.log(a)
console.log(b)
The problem is that map returns an array with replaced elements, while you want an object.
Since you are already using Lodash you could use mapValues to transform the values of an object and return an object instead of an array.
function pickKeys(dataObj, keys) {
return _.mapValues(dataObj, obj => _.pick(obj, keys));
}
function pickKeys(dataObj, keys) {
return _.mapValues(dataObj, obj => _.pick(obj, keys));
}
const dataset = {
"2019": {
"a": 1,
"b": 2,
"c": 3,
"d": 4
},
"2020": {
"a": 2,
"b": 4,
"c": 6,
"d": 8
},
"2021": {
"a": 10,
"b": 11,
"c": 12,
"d": 13
}
}
console.log(pickKeys(dataset, ["a", "c"]));
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>
You could map the wanted keys by using the entries of the given object.
const
dataset = { 2019: { a: 1, b: 2, c: 3, d: 4 }, 2020: { a: 2, b: 4, c: 6, d: 8 }, 2021: { a: 10, b: 11, c: 12, d: 13 } },
groups = [['a', 'c'], ['b', 'd']],
[result1, result2] = Object
.entries(dataset)
.reduce((r, [k, o]) =>
groups.map((group, i) =>
group.reduce(
(q, g) => ({ ...q, [k]: { ...q[k], [g]: o[g] } }),
r[i] || {}
)
),
[]
);
console.log(result1);
console.log(result2);
.as-console-wrapper { max-height: 100% !important; top: 0; }
The next provided example code is reduce based, generic but configurable in its usage ...
function createAndCollectSubdata(collector, dataEntry) {
const { keyLists, subdataList } = collector;
const [ dataKey, dataValue ] = dataEntry;
keyLists.forEach((keyList, idx) => {
const data = subdataList[idx] || (subdataList[idx] = {});
const subdata = data[dataKey] || (data[dataKey] = {}) ;
keyList.forEach(key => subdata[key] = dataValue[key]);
});
return collector;
}
const dataset = {
"2019": {
"a": 1,
"b": 2,
"c": 3,
"d": 4
},
"2020": {
"a": 2,
"b": 4,
"c": 6,
"d": 8
},
"2021": {
"a": 10,
"b": 11,
"c": 12,
"d": 13
}
};
const [
acSubdata,
bdSubdata
] = Object.entries(dataset).reduce(createAndCollectSubdata, {
keyLists: [["a", "c"], ["b", "d"]],
subdataList: []
}).subdataList;
console.log('acSubdata :', acSubdata);
console.log('bdSubdata :', bdSubdata);
.as-console-wrapper { min-height: 100%!important; top: 0; }
there is a way for merge array items by first item
_.merge({a: 1, c: [{y: 8}, {z: 9}]}, {b: 0, c: [{x: 5}]})
Result:
{
"a": 1,
"c": [
{
"y": 8,
"x": 5
},
{
"z": 9
}
],
"b": 0
}
what i want:
{
"a": 1,
"c": [
{
"y": 8,
"x": 5
},
{
"z": 9,
"x": 5 // <-------------------------
}
],
"b": 0
}
I want merge a source object by another used like a model. In case of array the model define only the first item of the collection and the source object should reflect the first model item into all the collection items.
I wouldn't actually do it, as it might be very confusing (especially when you've got an array with more than 1 item).
You can use _.mergeWith(), and manually iterate and merge array items.
const mrg = (o1, o2) => _.mergeWith(
o1, o2,
(a, b) => _.isArray(a) && _.isArray(b) ?
a.map((item, i) => mrg(item, b[Math.min(i, b.length - 1)]))
:
undefined
)
const result = mrg({a: 1, c: [{y: 8}, {z: 9}]}, {b: 0, c: [{x: 5}]})
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.14/lodash.js"></script>
Use _.mergeWith
function customizer(objValue, srcValue) {
if (_.isArray(objValue) && _.every(objValue, _.isObject) &&
_.isArray(srcValue) && _.every(srcValue, _.isObject) )
{
let newObj = Object.assign(...srcValue)
_.forEach(objValue, function(obj, index) {
objValue[index] = Object.assign(obj, newObj)
});
}
}
let a = {a: 1, c: [{y: 8}, {z: 9}]}
let b = {b: 0, c: [{x: 5}]}
let res = _.mergeWith(a, b, customizer)
Result:
{
"a": 1,
"c": [
{
"y": 8,
"x": 5
},
{
"z": 9,
"x": 5
}
],
"b": 0
}
I have an array:
[
{"a": a, "b": b, "c": c},
{"a": a, "b": b, "d": d},
{"a": a, "b": 2, "c": 3}
]
and I want to combine the first two objects because they have the same value for a and b into one, so that I will have a resulting array:
[
{"a": a, "b": b, "c": c, "d": d},
{"a": a, "b": 2, "c": 3}
]
Could someone help me figure out how to do this in pure JavaScript?
Thanks.
Hope this helps.
const array = [
{"a": 1, "b": 3, "c": 4},
{"a": 1, "b": 3, "d": 5},
{"a": 2, "b": 2, "c": 3}
];
const combine = (array) => {
const other = [];
let combined = {};
array.forEach((item) => {
if (!combined.a) combined = item;
else if (combined.a === item.a && combined.b === item.b) Object.assign(combined, item);
else other.push(item);
});
return other.concat(combined);
};
console.log(combine(array));