JS: Compare array of objects and add object to array if missing - javascript

Perhaps I'm over complicating this problem...
I have several arrays filled with objects that have one simple name: numeric value key-value paring.
I want to ensure all the arrays contain the same objects, and if they don't add an object/s to the array with a zero value.
array1 = [{'tool1': 24}]
array2 = [{'tool1': 2}, {'tool2': 21}, {'tool3': 1}]
array3 = [{'tool1': 23}, {'tool2': 13}, {'tool3': 2}, {'tool4': 10}]
array4 = [{'tool1': 18}, {'tool2': 29}, {'tool3': 19}, {'tool4': 10}]
// After the check and addition of objects, the final result of array1 and array2 would be:
array1 = [{'tool1': 24}, {'tool2': 0}, {'tool3': 0}, {'tool4': 0}]
array2 = [{'tool1': 2}, {'tool2': 21}, {'tool3': 1}, {'tool4': 0}]
// The other arrays would remain un-changed
Thank you for your time!

array1 = [{'tool1': 24}]
array2 = [{'tool1': 2}, {'tool2': 21}, {'tool3': 1}]
array3 = [{'tool1': 23}, {'tool2': 13}, {'tool3': 2}, {'tool4': 10}]
array4 = [{'tool1': 18}, {'tool2': 29}, {'tool3': 19}, {'tool4': 10}]
function myFunc(arr) {
for (let i = 1; i <= 4; i++) {
if (!arr.find(element => element['tool' + i])) {
let obj = {};
obj['tool' + i] = 0;
arr.push(obj);
}
}
}
myFunc(array1)
console.log('array1: ' + JSON.stringify(array1));
myFunc(array2)
console.log('array2: ' + JSON.stringify(array2));
myFunc(array3)
console.log('array3: ' + JSON.stringify(array3));
myFunc(array4)
console.log('array4: ' + JSON.stringify(array4));

Related

Javascript - join arrays of objects

I have method in a class that returns 8 arrays with 8 objects each:
[{...},{...},{...},{...},{...},{...},{...},{...}] [{...},{...},{...},{...},{...},{...},{...},{...}] etc.
the result I would like to get is one array containing all these objects, like this:
[{...},{...},{...},{...},{...},{...},{...},{...},{...},{...},{...},{...}] etc.
what function should I use to get this?
I tried with concat() but here I have to pass another array as a parameter...
You can use
arr.flat(depth);
This example is given in the mozilla javascript documentation:
var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]
var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]
var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]
Seems to be that .flat() is exactly what you need.
If you are simply trying to merge all the objects into a single array, one way to do this would be to use Array.reduce.
const result = [
[{}],
[{}],
[{}],
[{}],
[{}],
[{}],
[{}],
[{}]
];
const final = result.reduce( (acc, curr) => {
return [...acc, ...curr];
}, []);
console.log(final);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
Assuming the below as your array of objects structure
let array = [[{name: 1}, {name: 2}, {name: 3}], [{name: 1}, {name: 2}, {name: 3}], [{name: 1}, {name: 2}, {name: 3}]]
let out1 = [].concat.apply([], array)
console.log(out1)
If you use latest ES then you could try with this array.flat, as mentioned by sirko in the comments
let array = [[{name: 1}, {name: 2}, {name: 3}], [{name: 1}, {name: 2}, {name: 3}], [{name: 1}, {name: 2}, {name: 3}]]
let out2 = array.flat()
console.log(out2)

combining two arrays in specific format

I am trying to combine two arrays into one in a specific format. Please guide me on how i can achieve this.
let arr = [{'test' : 1}, {'test1' : 2}, {'test2': 3}, {'test3': 4}];
let arr1 = [{'testdo': 5}, {'testdo1': 6}, {'testdo2': 7}, {'testdo3': 8}];
// the resulted array should look like this.
arr3 = [{'test': 1}, {'testdo': 5}, {'test1': 2}, {'testdo1': 6}, {'test2': 3}, {'testdo2': 7},
{'test3': 4}, {'testdo3': 8}];
I have tried this
for(let i = 0; i<=6; i++){
let arr3: any = [arr[i], arr1[i]];
console.log(arr3);
}
Should work with arrays of any length.
let arr = [{'test' : 1}, {'test1' : 2}, {'test2': 3}, {'test3': 4}];
let arr1 = [{'testdo': 5}, {'testdo1': 6}, {'testdo2': 7}, {'testdo3': 8}];
let arr3 = [];
let max = Math.max(arr.length, arr1.length);
for (let i=0; i < max; i++) {
if (arr.length > i) {
arr3.push(arr[i]);
}
if (arr1.length > i) {
arr3.push(arr1[i]);
}
}
console.log(arr3);
Probably need something like:
const arr = [{test: 1}, {test1: 2}, {test2: 3}, {test3: 4}];
const arr1 = [{testdo: 5}, {testdo1: 6}, {testdo2: 7}, {testdo3: 8}];
const arr3 = [...arr];
let offset = 0;
arr1.forEach((arr1Item, index) => {
if (index <= arr?.length) {
const targetIndex = index + 1 + offset;
const removeCount = 0;
arr3.splice(targetIndex, removeCount, arr1Item);
offset += 1;
} else {
arr3.push(arr1Item);
}
});
arr3 now has the shape you probably need.
I hope this helps you.

Filter array of objects by common properties

Is it possible in some way to filter let's say such an array of object arrays:
[[{id: 1}, {id: 2}, {id: 3}], [{id:6}, {id: 2}], [{id: 2}, {id: 1}, {id: 9}, {id: 3}]]
To get array of objects which all arrays have the same property (id), so in this case it output will be:
[{id: 2}] // becasue this id is the same in all three subarrays
I've only try intersectionBy from loadash but it seems to work in completely other way :/
I would take one array (it's enough to take one because if the property is not there its already not common), in this example I'm taking the first one but probably more efficient will be picking the shortest one.
iterate over the array and check for each object if its common to all other arrays.
const arr = [[{id: 1}, {id: 2}, {id: 3}], [{id:6}, {id: 2}], [{id: 2}, {id: 1}, {id: 9}, {id: 3}]];
let firstArray = arr.shift();
const result = firstArray.reduce((common, item)=>{
if (arr.every(inner => inner.some(_item => _item.id === item.id))) {
common.push(item);
}
return common;
},[])
console.log(result);
Using Ramda:
const input = [[{id: 1}, {id: 2}, {id: 3}], [{id:6}, {id: 2}], [{id: 2}, {id: 1}, {id: 9}, {id: 3}]];
R.intersection(...input);
You can use array reduce,forEach , findIndex and sort to get the most common object. In first inside the reduce callback use forEach to iterate each of the child array and then use findIndex to find if in accumulator array , there exist an object with same id. If it does not exist create a new object with key id & occurrence. If it exist then increase the value of occurrence. This will give the most common id, even if an id is not present in few child array
let data = [
[{id: 1}, {id: 2}, { id: 3}],
[{id: 6}, {id: 2}],
[{id: 2}, {id: 1}, {id: 9}, { id: 3}]
];
let obj = data.reduce((acc, curr) => {
curr.forEach((item) => {
let getInd = acc.findIndex((elem) => {
return elem.id === item.id
});
if (getInd === -1) {
acc.push({
id: item.id,
occurence: 1
})
} else {
acc[getInd].occurence += 1;
}
})
return acc;
}, []).sort((a, b) => {
return b.occurence - a.occurence;
});
console.log(obj[0])
var arr = [
[{id: 1}, {id: 2}, {id: 3}],
[{id:6}, {id: 2}],
[{id: 2}, {id: 1}, {id: 9}, {id: 3}]
]
var obj = {};
var arrLength = arr.length;
arr.forEach((val,index) => {
val.forEach((item) =>{
if(index == 0){
if(!obj.hasOwnProperty(item.id)){
obj[item.id] = 1;
}
}else{
if(obj.hasOwnProperty(item.id)){
obj[item.id] = obj[item.id] + 1;
}else{
return;
}
}
});
});
var output = [];
for (const property in obj) {
if(obj[property] == arrLength){
output.push({
id: property
})
}
}
console.log(output);
My approach is similar to that of naortor, but with an attempt to be more generic.
const intersection = (pred) => (as, bs) =>
as .filter (a => bs .some (b => pred (a, b)))
const intersectionAll = (pred) => (xs) =>
xs.length ? xs .reduce (intersection (pred)) : []
const input = [[{id: 1}, {id: 2}, {id: 3}], [{id:6}, {id: 2}], [{id: 2}, {id: 1}, {id: 9}, {id: 3}]]
const eqIds = (a, b) => a .id == b .id
console .log (
intersectionAll (eqIds) (input)
)
.as-console-wrapper {min-height: 100% !important}
This version requires you to say how you identify two equal values. (We will check that they have the same id, but any binary predicate function is allowed.) This function is passed to intersection which returns a function that takes two arrays and finds all the element in common between those two. intersectionAll wraps this behavior up, folding intersection over an array of arrays.
This breakdown is useful, as intersection is a useful function on its own too. And abstracting out the id check into a function you need to supply means these functions are much more generic.

Combine objects from an array with the same date into new array of objects using Javascript

I have an array of objects that looks like this:
var data = [
{Date: "01-01-2000", Banana: 10},
{Date: "01-01-2000", Apple: 15},
{Date: "01-01-2000", Orange: 20},
{Date: "01-02-2000", Banana: 25},
{Date: "01-02-2000", Apple: 30},
{Date: "01-02-2000", Orange: 35}];
And I would like to know how to merge the objects in this array by the same date values so that the following array is returned:
data = [
{Date: "01-01-2000", Banana: 10, Apple: 15, Orange: 20},
{Date: "01-02-2000", Banana: 25, Apple: 30, Orange: 35}];
My apologies if this is a duplicate question, I just have not been able to find an example where the key & value pairs are different in each object and so I thought I would at least ask.
An alternative is using the function reduce to group the objects along with the function Object.values to extract the grouped objects.
var data = [{Date: "01-01-2000", Banana: 10},{Date: "01-01-2000", Apple: 15},{Date: "01-01-2000", Orange: 20},{Date: "01-02-2000", Banana: 25},{Date: "01-02-2000", Apple: 30},{Date: "01-02-2000", Orange: 35}],
result = Object.values(data.reduce((a, c) => {
a[c.Date] = Object.assign(a[c.Date] || {}, c);
return a;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Alternatively, you can use a for loop.
Try:
var data = [{Date: "01-01-2000", Banana: 10},{Date: "01-01-2000", Apple: 15},{Date: "01-01-2000", Orange: 20},{Date: "01-02-2000", Banana: 25},{Date: "01-02-2000", Apple: 30},{Date: "01-02-2000", Orange: 35}];
var obj = {};
for(var i = 0; i < data.length; i++){
var date = data[i].Date;
// Get previous date saved inside the result
var p_date = obj[date] || {};
// Merge the previous date with the next date
obj[date] = Object.assign(p_date, data[i]);
}
// Convert to an array
var result = Object.values(obj);
console.log(result);

Shifting array of elements into another index of the array

Not sure if this may be a duplicate, but I am having some troubles trying to think of the best way of shifting an element in an array filled of arrays of elements.
Such as:
var foo = [
[ {obj: 1}, {obj: 2}, {obj: 3}, {obj: 4} ],
[ {obj: 5}, {obj: 6}, {obj: 7}, {obj: 8} ],
[ {obj: 9}, {obj: 10}, {obj: 11}, {obj: 12} ]
];
If I remove one element given an arrayIndex, it would remove that element then shift all of the proceeding elements down to the appropriate array. Such as if I remove obj 3 the result would be:
var arrayIndex = 0;
var objIndex = 2;
var bar = foo[arrayIndex].splice(objIndex, 1);
Result:
bar = [
[ {obj: 1}, {obj: 2}, {obj: 4}, {obj: 5} ],
[ {obj: 6}, {obj: 7}, {obj: 8}, {obj: 9} ],
[ {obj: 10}, {obj: 11}, {obj: 12} ]
];
Another example would be as shown removing obj 8:
var arrayIndex = 1;
var objIndex = 3;
var bar = foo[arrayIndex].splice(objIndex, 1);
Result:
bar = [
[ {obj: 1}, {obj: 2}, {obj: 3}, {obj: 4} ],
[ {obj: 5}, {obj: 6}, {obj: 7}, {obj: 9} ],
[ {obj: 10}, {obj: 11}, {obj: 12} ]
];
The issue for me is shifting all of the proceeding elements into the correct array position. Additionally, I would like the empty array to be removed. Where foo's length would decrease. foo will also be mutated.
Here was my attempted jsfiddle: https://jsfiddle.net/mLw8kncn/1/
Any help would be appreciated.
A simple way is to store your items in 1D array instead of 2D. Then manipulate the indexes.
var foo = [ {obj: 1}, {obj: 2}, {obj: 3}, {obj: 4},
{obj: 5}, {obj: 6}, {obj: 7}, {obj: 8},
{obj: 9}, {obj: 10}, {obj: 11}, {obj: 12} ];
function remove(arrayIndex, objIndex) {
var realIndex = arrayIndex * 4 + objIndex;
foo.splice(realIndex, 1);
}
Otherwise, you have to rearrange items after every splice.
function remove(arrayIndex, objIndex) {
foo[arrayIndex].splice(objIndex, 1);
for (var i = arrayIndex + 1; i < foo.length; i++) {
var obj = foo[i].shift();
foo[i - 1].push(obj);
}
if (foo[foo.length - 1].length <= 0) {
foo.pop();
}
}
And this is much complicated.
You could use a function that flattens the array temporarily to 1 dimension (keeping record of the original sizes of the sub arrays), then applies the standard splice on that, and finally reconstructs the 2D array based on the recorded size information.
This will have as benefit you can use all the power of splice to delete more than one element at a time and/or insert other elements in the same operation.
The given index must therefore be the index as if the input array were 1-dimensional:
function splice2d(a, start, deleteCount /*, item1, item2, ...*/){
var flat = [], sizes = [];
// Make a flat array, keeping record of subarray sizes
while (a.length) {
sizes.push(a[0].length);
flat = flat.concat(a.shift());
};
// Apply original splice to flat array
[].splice.apply(flat, [].slice.call(arguments, 1));
// Reconstruct 2D array again based on sizes
while (sizes.length) {
a.push(flat.splice(0, sizes.shift()));
}
return a;
}
// Sample data
var foo =
[[{obj: 1}, {obj: 2}, {obj: 3}, {obj: 4}],
[{obj: 5}, {obj: 6}, {obj: 7}, {obj: 8}],
[{obj: 9}, {obj: 10}, {obj: 11}, {obj: 12}]]
// Mutate
splice2d(foo, 2, 1);
// Output result
console.log(foo);
I guess Array.prototype.reduce() is ideal for this job. You may do it like
var foo = [[{obj: 1}, {obj: 2}, {obj: 3}, {obj: 4}],
[{obj: 5}, {obj: 6}, {obj: 7}, {obj: 8}],
[{obj: 9}, {obj: 10}, {obj: 11}, {obj: 12}]
],
removeAndShift = (a,ai,oi) => ai == a.length-1 ? a[ai].splice(oi,1)
: a.reduce((p,c,i,a) => { if (i == ai+1) {
p.splice(oi,1);
p.push(c.shift());
}
i > ai+1 && p.push(c.shift());
return c;
});
removeAndShift(foo,1,3);
console.log(foo);
Note that we are not doing anything but simply splicing out the item to delete if the array item to remove an item from is at the very end.

Categories

Resources