Reputation: 79
So I have array of arrays like so:
array1 = [boot = [value = [ enable =["some string"]]]]
and an array of objects:
array2 = [options=[ enable=[]], boot =[value =[something =[]]]]
I need to merge array1 to array2 using the "path" of the names so that I get:
output = [options=[ enable=[]], boot =[value =[something[], enable =["some string"]]]
So I have to go through objects in depth, detect the common names of objects and push the rest of array1 in the right place in array2. Any idea how to do that? I tried a recursive function but it did not give me the expected result! Here is the function I wrote:
function mergeArrays(menu, array){
const arrayItem = Object.keys(array)[0];
var index = -1;
Object.values(menu).map(menuItem =>{
if(Object.keys(menuItem).indexOf(arrayItem) !== -1){
index = Object.keys(menuItem).indexOf(arrayItem);
}
})
if(index === -1){
menu.push(array);
return menu;
}else{
const menuItem = Object.values(menu)[index];
const rest = Object.values(menuItem);
const arrayItem = Object.values(array)[0];
mergeArrays(rest, arrayItem);
}
}
Upvotes: 0
Views: 147
Reputation:
Note that a = [ v = 1 ]
is an array, not an object. It's the same as v = 1; a = [ v ]
, which boils down to a = [ 1 ]
, and if you want to read the first value you have to write a[0]
. However, since your merging strategy is "based on the name of objects", it seems more appropriate to use a dictionary d = { v : 1 }
. In this case, you can get the value by its name with d["v"]
.
In the JavaScript world, people use the word "object" rather than "dictionary". No matter the word, what you need to remember is that objects and arrays are different since they inherit from different classes. Indeed, {}
means new Object()
, while []
means new Array()
. Also, most of the time people enumerate the properties of an object with a for ... in
loop, and iterate over the elements of an array either with a for ... of
loop or with a for
loop. Again, knowing that you are interested in the name of objects, the for ... in
loop is probably the best option for you.
That being said, despite of our discussion in the comments, it's still not perfectly clear to me what you are trying to achieve. Hence, I've decided to write a generic merging function. This function is able to merge any type of objects.1 Here is a couple of use cases :
> | merge("azerty", null) // b wins
< | null
> | merge("azerty", { t : true }) // b wins
< | { t : true }
> | merge({ t : true }, "azerty") // b wins
< | "azerty"
> | merge([1, 2, 3], [undefined, 5]) // a[0] wins, b[1] wins
< | [1, 5, 3]
> | merge("azerty", undefined) // a wins
< | "azerty"
The merging strategy is dead simple and can be summarized as follows :
If
a
is an array andb
is an array, or ifa
is a dictionary andb
is a dictionary, then merge them recursively, otherwise,b
always wins unless it'sundefined
.
main({
m : [ 1, { ms : "ms", mf : false }, 3 ],
n : { ns : "ns", na : [ null, undefined ] },
o : { os : "os" }
}, {
m : [ -1, { mt : true } ],
n : { nt : true, na : [ undefined, null ] }
});
function merge (a, b) {
if (isFunction(b)) {
return b;
} else if (isArray(b)) {
if (!isArray(a)) {
return b;
} else {
var max = Math.max(
a.length, b.length
);
for (var i = 0; i < max; i++) {
b[i] = merge(a[i], b[i]);
}
return b;
}
} else if (isComplex(b)) {
if (!isComplex(a) || isArray(a) || isFunction(a)) {
return b;
} else {
for (var k in a) {
b[k] = merge(a[k], b[k]);
}
return b;
}
} else if (b === undefined) {
if (isFunction(a)) {
return a;
} else if (isArray(a)) {
return merge(a, []);
} else if (isComplex(a)) {
return merge(a, {});
} else {
return a;
}
} else {
return b;
}
}
function main (a, b) {
var pre = document.getElementsByTagName("pre");
b = merge(a, b);
pre[0].textContent = "a = " + (
fixUndef(JSON.stringify(a, markUndef, 2))
);
pre[1].textContent = "b = " + (
fixUndef(JSON.stringify(b, markUndef, 2))
);
}
function isComplex (x) {
return x === Object(x);
}
function isArray (x) {
return x instanceof Array;
}
function isFunction (x) {
return typeof x === "function";
}
// JSON.stringify() replaces
// `undefined` with `null`, the
// below functions are meant to
// fix this behavior.
function markUndef (k, v) {
return v === undefined ? "UNDEF" : v;
}
function fixUndef (s) {
return s.replace("\"UNDEF\"", "undefined");
}
pre {
display : inline-block;
vertical-align: top;
width: 50%;
}
<pre></pre><pre></pre>
1 I leave it to you to prove the algorithm correctness before using this function :-P
Upvotes: 1
Reputation:
Javascript is not going to execute your array as you're expecting. i.e.
array1 = [boot = [value = [ enable =["some string"]]]]
is same as
[[[["some string"]]]]
therefore if you try to merge array1 and array 2 you will get :-
[[[["some string"]]],[[]],[[[]]]]
I don't know what you're trying to achieve but in my opinion you should be using object instead.
Welcome
Upvotes: 1