How to unite 2 arrays with objects without repetition in JS - javascript

I have 2 objects.
const obj1 = [{a: 1, b: 2}, {a: 2, b: 4}, {a: 8, b: 3}];
const obj2 = [{a: 1, b: 2}, {a: 3, b: 4}, {a: 8, b: 3}, {a: 7, b: 3}];
And I want to unite them in one but without repetitions.
the result should be obj3 = [{a: 1, b: 2}, {a: 2, b: 4}, {a: 3, b: 4}, {a: 8, b: 3}, {a: 7, b: 3}];
const obj3 = obj1.map((item) => obj2.filter((i) => i !== item));
is not working.

You can always try to loop through the first one and loop through the second one for each entry, checking for repetition.

It's handy to use the lodash library to handle array operations like the one you're asking about:
https://lodash.com/docs/4.17.15#union
var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
_.unionWith(objects, others, _.isEqual);
// => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
It's easy to add the lodash library to your code. You can download and save the lodash.js file here: https://lodash.com/, or just use a url from a CDN and include with your other scripts/script tags: https://cdnjs.com/libraries/lodash.js

The problem is you are mapping over an array, so basically you will do the filter every obj1.length time.
In term of the filter, filter will remove all the same item in obj1 and you will only get the not duplicate item in obj2, you could group them.
Another good solution I would suggest is to concat the two array and filter it.
const obj1 = [{a: 1, b: 2}, {a: 2, b: 4}, {a: 8, b: 3}];
const obj2 = [{a: 1, b: 2}, {a: 3, b: 4}, {a: 8, b: 3}, {a: 7, b: 3}];
let obj3 = obj1.concat(obj2)
let obj4=obj3.filter((item,index) => obj3.indexOf(item) === index)
console.log(obj4)

Related

I want to create an object with the key as a property from the object and value as an array of objects matching the key (javascript)

I have a given object to iterate and create another object in the below format (newObj)
Given object:
let obj = [
{a: 1, b: 232},
{a: 1, b: 2},
{a: 1, b: 256},
{a: 2, b: 3},
{a: 2, b: 3343},
{a: 3, b: 4}
];
Expected object:
newObj = {
1: [{a: 1, b: 232}, {a: 1, b: 2}, {a: 1, b: 256}],
2: [{a: 2, b: 3}],
3: [{a: 3, b: 4}]
}
Code:
let newObj = {};
obj.forEach(element => {
if (newObj[element.a]) {
let key = element.a;
newObj[key] = newObj[key].push(element);
}
newObj[element.a] = [element];
});
console.log(newObj);
We create a result object, loop through every object in obj array, if we don't have the object a key in the result object, we add him (a: []), and after that we push the entire object to result[a] array
let obj = [
{a: 1, b: 232},
{a: 1, b: 2},
{a: 1, b: 256},
{a: 2, b: 3},
{a: 2, b: 3343},
{a: 3, b: 4}
];
let result = {};
for(const {a, b} of obj) {
if(!result[a]) result[a] = []
result[a].push({a, b})
}
console.log(result)
To address your updated code snippet, you need to only create a new array for a given key if they key does not exist.
let obj = [
{ a: 1, b: 232 },
{ a: 1, b: 2 },
{ a: 1, b: 256 },
{ a: 2, b: 3 },
{ a: 2, b: 3343 },
{ a: 3, b: 4 }
];
let newObj = {};
obj.forEach(element => {
let key = element.a;
if (!newObj[key]) {
newObj[key] = []; // Only initialize if undefined/null
}
newObj[key].push(element); // Always push
});
console.log(newObj);
.as-console-wrapper { top: 0; max-height: 100% !important; }
A more modern approach would be to simply bin them by the a key by reducing and spreading.
const obj = [
{ a: 1, b: 232 },
{ a: 1, b: 2 },
{ a: 1, b: 256 },
{ a: 2, b: 3 },
{ a: 2, b: 3343 },
{ a: 3, b: 4 }
];
const newObj = obj.reduce((acc, o) => ({
...acc,
[o.a]: [...(acc[o.a] ?? []), o]
}), {});
console.log(newObj);
.as-console-wrapper { top: 0; max-height: 100% !important; }
you can use reduce for that
let obj = [
{a: 1, b: 232},
{a: 1, b: 2},
{a: 1, b: 256},
{a: 2, b: 3},
{a: 2, b: 3343},
{a: 3, b: 4}
];
const newObj = obj.reduce((res, {a, b}) => {
return {
...res,
[a] : [...(res[a] || []), {a, b}]
}
}, {})
console.log(newObj)

Finding all the keys in the array of objects

Given that I have an array that is return from database that contains object,
var jsObjects = [
{a: 1, b: 2},
{a: 3, b: 4, c: 66},
{a: 5, b: 6, c: 55, d: 66},
{a: 7, b: 8, c: 12, e: 15}
];
How can I get all the keys of the object? I've been using this to obtain the keys, however I notice that index 0 wont always have all the keys. Hence problem lays.
let columns = Object.keys(jsObjects[0]),
However, the first index won't always have all the columns.
My desired output:
["a", "b", "c", "d", "e"]
Sets are good at removing duplicates:
const jsObjects = [
{a: 1, b: 2},
{a: 3, b: 4, c: 66},
{a: 5, b: 6, c: 55, d: 66},
{a: 7, b: 8, c: 12, e: 15}
];
const keys = [...new Set(jsObjects.flatMap(Object.keys))];
console.log(keys);
You could create an object with the count of the keys and get the keys from counts.
const
objects = [{ a: 1, b: 2 }, { a: 3, b: 4, c: 66 }, { a: 5, b: 6, c: 55, d: 66 }, { a: 7, b: 8, c: 12, e: 15 }],
result = Object.keys(objects.reduce((r, o) => {
Object.keys(o).forEach(k => r[k] = true);
return r;
}));
console.log(result);
You can use a Set(), which is like an array with the exception that it doesn't allow multiple occurances of elements.
var jsObjects = [
{a: 1, b: 2},
{a: 3, b: 4, c: 66},
{a: 5, b: 6, c: 55, d: 66},
{a: 7, b: 8, c: 12, e: 15}
];
var keys = new Set();
for(object of jsObjects) {
for(key in object) {
keys = keys.add(key);
}
}
for (const key of keys) {
console.log(key);
}
I tried this solution: iterating on jsObjects elements and pushing keys
into columns array if not present.
var jsObjects = [
{a: 1, b: 2},
{a: 3, b: 4, c: 66},
{a: 5, b: 6, c: 55, d: 66},
{a: 7, b: 8, c: 12, e: 15}
];
let columns = [];
jsObjects.forEach(
o => {
Object.keys(o).forEach(
t => {
if (columns.indexOf(t) < 0 ) {
columns.push(t);
}
}
)
}
)
console.log(columns);

Array of properties of objects in an array

Given the array of objects:
data = [{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}, {a: 7, b: 8, c: 9}]
How can I get an array of only a elements of the objects? Something like this:
a = [1, 4, 7]
Is it possible without iterating through the objects?
This is easy to achieve with .map()
var data = [{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}, {a: 7, b: 8, c: 9}];
var a = data.map(obj => obj.a);
console.log(a);
You can also try this:
var result = data.reduce(function(result, obj) {
return result.concat(obj.a);
}, []);
There are several methods.
You should look into Array.map() or the powerful Lodash library.
let aElements = data.map(o => o.a);
Using functional programming(map higher-order function):
var a = data.map(function(obj){return obj.a});
or the same in es6:
let a = data.map(obj=>obj.a);
But, nevertheless, technically Array.prototype.map iterates.

Lodash Not executing the nested method,

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>

What's the right way to sort the child object by their property in a Map in Immutable.js

I have an Map m:
var m = Immutable.fromJS({
first: {a: 6, b: 3},
second: {a: 3, b: 6},
third: {a: 2, b: 4}
})
I want to get the child objects in m sorted by their property b, like this:
[
{a: 6, b: 3},
{a: 2, b: 4},
{a: 3, b: 6}
]
I have tried below:
m.valueSeq().sort(function(a, b) {
return a.get('b') > b.get('b')
}).toJS()
It works well in Chrome and node.js, but in Safari v8.0 in OS X, the result is
[
{a: 6, b: 3},
{a: 3, b: 6},
{a: 2, b: 4}
]
It did not sort at all! This made some bugs in my React/Redux app. What's the matter of it? And what is the right way to sort it? Thanks!
Your custom compare function requires the returning of 1, -1 or 0 in order to sort the items correctly.
m.valueSeq().sort(function(a, b) {
if (a.get('b') > b.get('b')) return 1;
if (a.get('b') < b.get('b')) return -1;
else return 0;
}).toJS();

Categories