Merge objects from two arrays of object based in the index - javascript

i searched a lot about this but i do not find anything that can enlight me about my issue:
I have this code:
let array1 = ["a", "b", 3, {
p1: 'hola'
}, "c", "d"],
array2 = [1, 2, {
p1: 'adios'
}],
result = [],
i, l = Math.min(array1.length, array2.length);
for (i = 0; i < l; i++) {
if (typeof array1[i] === 'object' && typeof array2[i] === 'object') {
result.push(array2[i], ...(JSON.stringify() === JSON.stringify() ?
[] :
[array1[i]]
));
} else {
result.push(array2[i], array1[i]);
}
}
result.push(...array1.slice(l), ...array2.slice(l));
console.log(result);
i have modified the code with the suggestions, right now the code does this:
we have two array;
array1 = ["a", "b", 3, {p1: 'hello'},"c", "d"]
array2 = [1, 2, {p1: 'hello'}]
the result right now is this based in the code:
result: [1, 'a', 2, 'b', {p1: 'hello'}, 3, {p1: 'hello'}, 'c', 'd']
this work fine because i dont want to omit objects that are in different index between the two array, the problem right now is that when the objects in the two array are in the same index this code;
array1 = ["a", "b", {p2: 'goodbye'},"c", "d"]
array2 = [1, 2, {p1: 'hello'}]
result : [1, 'a', 2, 'b', {p1: 'hello'}, 'c', 'd']
This is my issue right now, what i want is that when there are object in the same index on two array compare the properties of the objects and is the same skip the first array object and pass the second to the final array, but if the properties are not the same, combine the properties of the object in one, this is the ideal result that i want:
array1 = ["a", "b", {p2: 'goodbye'},"c", "d"]
array2 = [1, 2, {p1: 'hello'}]
result : [1, 'a', 2, 'b', {p1: 'hello', p2: 'goodbye'}, 'c', 'd']

I think this is what you're after.
let array1 = ['a', 'b', { p2: 'goodbye' }, 'c', 'd'];
let array2 = [1, 2, { p1: 'hello' }];
let result = [];
for (let i = 0; i < Math.max(array1.length, array2.length); i++) {
if (typeof array1[i] == 'object' && typeof array2[i] == 'object') {
result.push({ ...array2[i], ...array1[i] });
} else {
array2[i] && result.push(array2[i]);
array1[i] && result.push(array1[i]);
}
}
console.log(result);

You could compare the items and if same omit the second item.
let array1 = ["a", "b", {p1: 'hello world'},"c", "d"],
array2 = [1, 2, {p1: 'hello world'}],
result = [],
i, l = Math.min(array1.length, array2.length);
for (i = 0; i < l; i++) {
result.push(array2[i], ...(JSON.stringify() === JSON.stringify()
? []
: [array1[i]]
));
}
result.push(...array1.slice(l), ...array2.slice(l));
console.log(result);

Related

How to merge two arrays in JavaScript loop

Is there a better way to do this? Faster or more readable? Please share your approach.
const a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
const b = [ 'a', 'b', 'c', 'd', 'e', 'f' ]
let i = 0
let j = 1
while (true) {
const item = b[i]
if (!item) break
a.splice(j, 0, item)
j += 2
i++
}
// expected output [0, 'a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 5, 'f', 6, 7, 8, 9]
You could iterate the array by the minimum of both array lengths and take the rest by slicing the arrays from the minimum length.
function merge(a, b) {
const
result = [];
l = Math.min(a.length, b.length);
for (let i = 0; i < l; i++) result.push(a[i], b[i]);
result.push(...a.slice(l), ...b.slice(l));
return result;
}
console.log(...merge([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], ['a', 'b', 'c', 'd', 'e', 'f']));
You can use either recursion:
const Nil =
Symbol();
const intercalate =
([x=Nil, ...xn], [y=Nil, ...yn], ret=[]) =>
x === Nil && y === Nil
? ret
: intercalate(xn, yn, ret.concat( x === Nil ? [] : x
, y === Nil ? [] : y
));
Or Array#flatMap:
const intercalate =
(xn, yn) =>
xn.flatMap((x, i) =>
i >= yn.length
? [x]
: [x, yn[i]]);
My approach:
function mergeBetween(a, b) {
let i = 0
let j = 1
while (true) {
const item = b[i]
if (!item) break
a.splice(j, 0, item)
j += 2
i++
}
return a
}
const a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
const b = [ 'a', 'b', 'c', 'd', 'e', 'f' ]
mergeBetween(a, b) //[0, 'a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 5, 'f', 6, 7, 8, 9]
This would be my approach, if speed is your game, then you should stick to for loops... But I would suggest avoiding premature optimization in general... Not sure if that is what you meant by "faster" either...
const a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
const b = ["a", "b", "c", "d", "e", "f"];
// check which is longer
const longer = a.length > b.length ? a : b;
const shorter = a.length < b.length ? a : b;
// declare a new variable to hold the combined array
let newArray = [];
for (let i = 0; i < longer.length; i++)
newArray =
i < shorter.length
? [...newArray, longer[i], shorter[i]]
: [...newArray, longer[i]];
console.log(newArray)

Convert object with multiple arrays to array of objects

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)

Compare two arrays containing objects including other objects, arrays, etc

Look at these examples of array comparative code:
// example-1
let array1 = ['a', 'b'];
let array2 = ['a', 'b'];
console.log(array1.equals(array2)); // returns true
// example-2
let array1 = ['a', 'b', 1];
let array2 = ['a', 'b', 1];
console.log(array1.equals(array2)); // returns true
// example-3
let array1 = ['a', 'b', {'a': 1, 'b': 2}];
let array2 = ['a', 'b', {'b': 2, 'a', 1}];
console.log(array1.equals(array2)); // returns false
I'm looking for a way to compare the arrays containing objects in them, but irrespective of the order of elements in a nested object, like mentioned in the example-3 above.
You should JSON.stringify() the arrays and compare them like so:
var arr1 = ['a', 'b', {'a': 1}];
var arr2 = ['a', 'b', {'a': 1}];
console.log(JSON.stringify(array1) == JSON.stringify(array2));
This works because it converts arrays of objects into a much simpler comparative state (JSON strings). This will only work if the arrays contain their properties in the same ordered in the OP's example.
underscore way:
_.isEqual(array1, array2)
You can use JSON.stringify() to get the JSON string and compare them with ===:
let array1 = ['a', 'b', {'a': 1}];
let array2 = ['a', 'b', {'a': 1}];
console.log(JSON.stringify(array1) === JSON.stringify(array2)); // returns true
You can just write a function the will recursively check until it gets down to primitives. For example:
function deepEqual(o1, o2){
if (Array.isArray(o1)) {
return Array.isArray(o2)
&& o1.length === o2.length
&& o1.every((item, idx) => deepEqual(item, o2[idx]))
}
if (typeof(o1) == 'object' && o1 != null){ // (typeof null == 'object)
return typeof(o2) == 'object'
&& o2 != null
&& deepEqual(Object.entries(o1)
.sort((a,b) => a[0].localeCompare(b[0])),Object.entries(o2).sort((a,b) => a[0].localeCompare(b[0])))
}
return o1 === o2
}
//Object order doesn't matter
let ob1 = [1, 2, {a: "test", b:"hello"}, 4]
let ob2 = [1, 2, {b:"hello", a: "test", }, 4]
console.log(deepEqual(ob1, ob2))
ob1 = [1, 2, {a: "test", b:"hello"}, 4]
ob2 = [1, 2, {b:"hello", a: "non-test", }, 4]
console.log(deepEqual(ob1, ob2))
// array order matters:
ob1 = [2, 1, {a: "test", b:"hello"}, 4]
ob2 = [1, 2, {b:"hello", a: "test", }, 4]
console.log(deepEqual(ob1, ob2))
console.log(deepEqual("test", "test"))
console.log(deepEqual(null, {a:"test"}))
// etc.

Map 2 array into 1 array object

I have 2 separate array but both of them have same length. How to merge them together into an array object so that it's easy to populate later?
for example
[1,2,3,4,5]
['a','b','c','d','e']
I expect I can have something like
[{'index':1,'value':'a'},{'index':2,'value':'b'}]
I've tried
$.each(a, function(i,x){
$.each(b, function(i,z){
c['index'] = x;
c['value'] = z;
});
});
But I got only [{'index':'1','value':'a'}]
You can use map() for iterate and generate the new array
var arr1 = [1, 2, 3, 4, 5],
arr2 = ['a', 'b', 'c', 'd', 'e'];
var res = arr1.map(function(v, i) {
return {
index: v,
value: arr2[i]
};
})
document.write('<pre>' + JSON.stringify(res, null, 3) + '</pre>');
With ES6 you can do it with arrow function like below:
const arr1 = [1, 2, 3, 4, 5];
const arr2 = ["a", "b", "c", "d", "e"];
const output = arr1.map((el, i) => ({ index: el, value: arr2[i] }));
console.log(output);

How to pivot a javascript array

I have this javascript array:
[['a', 'x', 1],
['a', 'y', 2],
['b', 'x', 3],
['b', 'z', 4],
['c', 'y', 5],
['c', 'z', 6]]
How do I pivot it to something like below with the 2nd column ('x', 'y', 'z') from above going across.
[['a', 1, 2, null],
['b', 3, null, 4],
['c', null, 5, 6]]
EDIT:
Sorry I was unclear. The answers so far seem to be referencing a static length/value for x, y, z. The array will be dynamic and can have anything in the 2nd column (ex. 't','u','v','w' instead of 'x','y','z'). I think I need to fill the array up first with nulls for all the possible combinations and then push in the values.
Thanks..
Going by Fabricio's comment, here is how you can accomplish something similar:
var result = {};
for(var i=0;i< basearray.length;i++){
if(!result[basearray[i][0]]){
result[basearray[i][0]]={};
}
result[basearray[i][0]][basearray[i][1]]=basearray[i][2];
}
Note that this returns an object or hashmap, not strictly an array, but the data is more organised and it can easily be turned into an array if you so wish. Here is a demonstration (check your console).
By adding this code:
var count=0;
for(var key in result){
result[count]=[];
result[count][0]=key;
result[count][1]=result[key].x||null;
result[count][2]=result[key].y||null;
result[count][3]=result[key].z||null;
count++;
}
your result object now simulates both structures, your original array of arrays, and the suggested key value pairs. You can see the results here: http://jsfiddle.net/9Lakw/3/
Here is what result looks like:
{
"a":{
"x":1,
"y":2
},
"b":{
"x":3,
"z":4
},
"c":{
"y":5,
"z":6
},
"0":[
"a",
1,
2,
null
],
"1":[
"b",
3,
null,
4
],
"2":[
"c",
null,
5,
6
]
}
Here's how I'd do it, with arrays and null fillers as in the question. This assumes that coords for given points always come in succession.
var arr = [['a', 'x', 1],
['a', 'y', 2],
['b', 'x', 3],
['b', 'z', 4],
['c', 'y', 5],
['c', 'z', 6]];
var aux = {
x: 1,
y: 2,
z: 3
},
output = [],
lastItem,
currItem;
for (var i = 0; i < arr.length; i++) {
currItem = arr[i];
if (currItem[0] !== lastItem) {
lastItem = currItem[0];
output.push([lastItem, null, null, null]);
}
output[output.length-1][aux[currItem[1]]] = currItem[2];
}
console.log(output); //[["a", 1, 2, null], ["b", 3, null, 4], ["c", null, 5, 6]]
Fiddle
Are you sure that's the format you want? It seems more sensible to get:
{
a: {x: 1, y: 2},
b: {x: 3, z: 4},
c: {y: 5, z: 6}
}
Which you can get from:
var results = {};
data.forEach(function(el) {
var name = el[0];
var prop = el[1];
var value = el[2];
results[name] = results[name] || {};
results[name][prop] = value;
})

Categories