Sum string arrays and subarrays in javascript without concatenating them - javascript
I am trying to "sum" the items from one array to another, preserving their children (subarrays):
array1 = [ array2 = [ array3 = [
[ [ [
"A", "1", "A",
"B", "2", "B",
[ [ "1",
"C" + "3" = "2",
] ] [
], ], "C",
"D" "4" "3"
] ] ]
],
"D",
"4"
]
Edit: Ideally the longest array would be treated as the "main" array (its values would come before the shortest array).
If the arrays have the same number of elements, the first array is the main.
["a", ["b", "c"], "d"]
+
["x", ["v", "w"], "y"]
=
["a" "x", ["b", "c", "v", "w"], "d", "y"]
["a", "b", ["c", "d", ["e", "f"]]]
+
[["1", ["2"]]]
=
["a", "b", ["c", "d", "1", ["e", "f", "2"]]]
Would it be possible? so far the only suggestions I've found are related to the use of .concat(), however it concatenates one array at the end of the other, and does not merge both:
var array1 = [["A", "B", ["C"]], "D"];
var array2 = [["1", "2", ["3"]], "4"];
console.log(array1.concat(array2)) // returns [["A", "B", ["C"]], "D", ["1", "2", ["3"]], "4"]
Edit 2:
I've been thinking about the problem in a different way now, and realized that an easy way to visualize it is like this:
target = [
"A",
"B",
[
"C",
"D",
[
"E"
],
"J"
]
]
I want to add the following element after "E":
newelement = [
[
[
"F",
[
"G",
"H",
"I"
]
]
]
]
the result would be:
result = [
"A",
"B",
[
"C",
"D",
[
"E",
"F",
[
"G",
"H",
"I"
]
],
"J"
]
]
so that's basically it, merging one array with another.
If I understand correctly you want to concat subsections of both arrays that consist only of non-arrays (the number of elements may differ), then merge the next arrays of both recursively, and then apply again the first logic to the next subsections having no arrays... etc.
Here is that idea implemented:
function deepConcat(a, b) {
if (a.length < b.length) return deepConcat(b, a);
let i = 0, j = 0, result = [];
while (true) {
while (i < a.length && !Array.isArray(a[i])) result.push(a[i++])
while (j < b.length && !Array.isArray(b[j])) result.push(b[j++])
if (i >= a.length || j >= b.length) break;
result.push(deepConcat(a[i++], b[j++]));
}
return [...result, ...a.slice(i), ...b.slice(j)];
}
const test = (a, b) => console.log(JSON.stringify(deepConcat(a, b)));
test([["A", "B", ["C"]], "D"], [["1", "2", ["3"]], "4"]);
test(["a", ["b", "c"], "d"], ["x", ["v", "w"], "y"]);
test(["a", "b", ["c", "d", ["e", "f"]]], [["1", ["2"]]]);
test(["A","B",["C","D",["E"],"J"]], [[["F",["G","H","I"]]]]);
Something like this?
array1 = [
["A", "B", ["C"]], "D"
]
array2 = [
["1", "2", ["3"]], "4"
]
array3 = [
["A", "B", "1", "2", ["C", "3"]], "D", "4"
]
const findFirstNonPrimitiveIndex = arr => arr.findIndex(x => !isPrimitive(x))
const takePrimitives = (arr, pos = 0) => arr.slice(0, findFirstNonPrimitiveIndex(arr))
const isPrimitive = x => typeof x !== "object"
const merge = (arr1, arr2) => {
const [head1, ...rest1] = arr1
const [head2, ...rest2] = arr2
// base case
if (rest1.length === 0)
if (isPrimitive(head1)) return [head1, head2];
else return [merge(head1, head2)]
// inductive step
if (isPrimitive(head1)) {
const cutPoint = findFirstNonPrimitiveIndex(rest1);
return [
...takePrimitives(arr1),
...takePrimitives(arr2),
...merge(rest1.slice(cutPoint), rest2.slice(cutPoint))
]
} else {
return [merge(head1, head2), ...merge(rest1, rest2)];
}
}
const result = merge(array1, array2);
console.log(result)
.as-console-wrapper {
top: 0;
max-height: 100% !important;
}
Related
How to remove duplicates array in multidimensional array where the key positions might not same in JavaScript?
let originalArray = [ ["A", "B", "C"], ["B", "A", "C"], ["D", "E", "F"] ]; let uniqueArray = originalArray.filter((item, index, self) => { return index === self.findIndex((t) => JSON.stringify(t) === JSON.stringify(item)); }); console.log(uniqueArray); I want this result: [ ["A", "B", "C"], ["D", "E", "F"] ]; To remove duplicates from a multidimensional array in JavaScript, where the key positions might not be the same, you can use a combination of Array.prototype.map(), Array.prototype.filter(), and Array.prototype.includes() to create a new array with only unique elements.
You can use an object with Array.prototype.reduce, storing a stringified version of the sorted values as the cache. let originalArray = [ ["A", "B", "C"], ["B", "A", "C"], ["D", "E", "F"] ]; let uniqueArray = Object.values(originalArray.reduce((acc, cur) => { const data = [...cur].sort(); const key = JSON.stringify(data); acc[key] = acc[key] ?? cur; return acc; }, {})); console.log(uniqueArray);
You can sort the inner arrays before inserting them into a Set for filtering. let originalArray = [ ["A", "B", "C"], ["B", "A", "C"], ["D", "E", "F"] ]; let vis = new Set; let res = originalArray.filter(x => { const str = JSON.stringify([...x].sort()); return !vis.has(str) && vis.add(str); }); console.log(res);
Merging array of arrays
The problem, I'm trying to solve is as followed we do have an array const array = [[1, 2, 3], ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"],["+", "-", "*", "/", "?"]]; we want to have an output like this: const output = [[1,"A","+"],[1,"A","-"],[1,"A","*"],[1,"A","/"],[1,"A","?"],[1,"B","+"],[1,"B","-"],[1,"B","*"],[1,"B","/"],[1,"B","?"],[1,"C","+"],[1,"C","-"],[1,"C","*"],[1,"C","/"],[1,"C","?"],[1,"D","+"],[1,"D","-"],[1,"D","*"],[1,"D","/"],[1,"D","?"],[1,"E","+"],[1,"E","-"],[1,"E","*"],[1,"E","/"],[1,"E","?"],[1,"F","+"],[1,"F","-"],[1,"F","*"],[1,"F","/"],[1,"F","?"],[1,"G","+"],[1,"G","-"],[1,"G","*"],[1,"G","/"],[1,"G","?"],[1,"H","+"],[1,"H","-"],[1,"H","*"],[1,"H","/"],[1,"H","?"],[1,"I","+"],[1,"I","-"],[1,"I","*"],[1,"I","/"],[1,"I","?"],[1,"J","+"],[1,"J","-"],[1,"J","*"],[1,"J","/"],[1,"J","?"],[2,"A","+"],[2,"A","-"],[2,"A","*"],[2,"A","/"],[2,"A","?"],[2,"B","+"],[2,"B","-"],[2,"B","*"],[2,"B","/"],[2,"B","?"],[2,"C","+"],[2,"C","-"],[2,"C","*"],[2,"C","/"],[2,"C","?"],[2,"D","+"],[2,"D","-"],[2,"D","*"],[2,"D","/"],[2,"D","?"],[2,"E","+"],[2,"E","-"],[2,"E","*"],[2,"E","/"],[2,"E","?"],[2,"F","+"],[2,"F","-"],[2,"F","*"],[2,"F","/"],[2,"F","?"],[2,"G","+"],[2,"G","-"],[2,"G","*"],[2,"G","/"],[2,"G","?"],[2,"H","+"],[2,"H","-"],[2,"H","*"],[2,"H","/"],[2,"H","?"],[2,"I","+"],[2,"I","-"],[2,"I","*"],[2,"I","/"],[2,"I","?"],[2,"J","+"],[2,"J","-"],[2,"J","*"],[2,"J","/"],[2,"J","?"],[3,"A","+"],[3,"A","-"],[3,"A","*"],[3,"A","/"],[3,"A","?"],[3,"B","+"],[3,"B","-"],[3,"B","*"],[3,"B","/"],[3,"B","?"],[3,"C","+"],[3,"C","-"],[3,"C","*"],[3,"C","/"],[3,"C","?"],[3,"D","+"],[3,"D","-"],[3,"D","*"],[3,"D","/"],[3,"D","?"],[3,"E","+"],[3,"E","-"],[3,"E","*"],[3,"E","/"],[3,"E","?"],[3,"F","+"],[3,"F","-"],[3,"F","*"],[3,"F","/"],[3,"F","?"],[3,"G","+"],[3,"G","-"],[3,"G","*"],[3,"G","/"],[3,"G","?"],[3,"H","+"],[3,"H","-"],[3,"H","*"],[3,"H","/"],[3,"H","?"],[3,"I","+"],[3,"I","-"],[3,"I","*"],[3,"I","/"],[3,"I","?"],[3,"J","+"],[3,"J","-"],[3,"J","*"],[3,"J","/"],[3,"J","?"]] We dont't know the size of the parent Array and children can have various sizes and types
#pilchard has point out this solution: All possible combinations of a 2d array in Javascript function combos(list, n = 0, result = [], current = []){ if (n === list.length) result.push(current) else list[n].forEach(item => combos(list, n+1, result, [...current, item])) return result } I can confirm that it works
#Andrew I tried this approach let me know if it will work. const array = [ [1, 2, 3], ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"], ["+", "-", "*", "/", "?"] ]; let result; let innerArray; innerArray = array[0].map(a1 => array[1].map(a2 => array[2].map(a3 => [a1, a2, a3]) ) ) result = innerArray.flat(2) console.log("Result", result)
You can use an inner map: const array = [ [1, 2, 3], ['A', 'B', 'C'], ['+', '-', '*'] ]; const res = array.map((e, i) => array.map(f => f[i])) console.log(res)
Sort an object and remove duplicates
Given an object like this. How to write a function that will return the object with sorted keys and remove the duplicates from the first value e.g const initialObj={ "2": ["A", "B", "D", "A"], "1": ["A", "B", "C"], }; const output = { "1": ["C"], "2": ["A", "B", "D"], } initial = { "1": ["C", "F", "G"], "2": ["A", "B", "C"], "3": ["A", "B", "D"], } output = { "1": ["F", "G"], "2": ["C"], "3": ["A", "B", "D"], }
const initialObj= { "1": ["C", "F", "G"], "2": ["A", "B", "C"], "3": ["A", "B", "D"], } function sortAndRemove(obj) { var keys = Object.keys(obj) keys.sort().reverse() seenBefore = new Set() answer = {} for (var key of keys) { for (var value of obj[key]) { if (!seenBefore.has(value)) { answer[key] = [...(answer[key] || []), value] seenBefore.add(value) } } } return answer } console.log(sortAndRemove(initialObj))
Considering the case that I got the algorithm you described, the following snippet would do the trick: const initial1 = { "2": ["A", "B", "D", "A"], "1": ["A", "B", "C"], }; const initial2 = { "1": ["C", "F", "G"], "2": ["A", "B", "C"], "3": ["A", "B", "D"], } // removing duplicates from array const removeDuplicates = ({ arr, toRemove }) => { return arr.filter(char => !toRemove.includes(char)) } // returns a sorted array! const sortObjKeys = (obj) => { const entries = Object.entries(obj) const sorted = entries.sort(([key1], [key2]) => { return Number(key1) - Number(key2) }) return sorted } // iterating over the sorted array (starting from the end) const reducer = (sorted) => { const { ret } = sorted.reverse().reduce((a, [key, val]) => { const cleared = removeDuplicates({ arr: [...new Set([...val])], toRemove: a.toRemove }) a.ret = [ [key, cleared], ...a.ret, ] a.toRemove = [...new Set([...a.toRemove, ...val])] return a }, { ret: [], toRemove: [] }) return ret } // putting it all together const processSortedArr = (obj) => { const sorted = sortObjKeys(obj) const ret = reducer(sorted) return Object.fromEntries(ret) } console.log('output1', processSortedArr(initial1)) console.log('output2', processSortedArr(initial2))
Here is a set of tools Assuming the keys are strings and not numbers If you want numerical sort, we need to cast to int const deDupe = (arr1,arr2) => arr1.filter(val => !arr2.includes(val)); const sortDedupe = obj => { const newObj = {} const order = Object.keys(obj); // get the keys order.sort(); // sort them order.forEach(key => newObj[key] = obj[key]); // reorder the object for (let i=0;i<order.length-1;i++) { newObj[order[i]] = deDupe(newObj[order[i]],newObj[order[i+1]]); //dedupe based on next } const last = order.pop() newObj[last] = [...new Set(newObj[last])]; // dedupe last return newObj } const initialObj={ "2": ["A", "B", "D", "A"], "1": ["A", "B", "C"], }; /* const output = { "1": ["C"], "2": ["A", "B", "D"], }*/ const initial = { "1": ["C", "F", "G"], "2": ["A", "B", "C"], "3": ["A", "B", "D"], } /* output = { "1": ["F", "G"], "2": ["C"], "3": ["A", "B", "D"], }*/ let output1 = sortDedupe(initialObj) console.log(output1) let output2 = sortDedupe(initial) console.log(output2)
Use index of array to find the corresponding index in a filtered version of that array
Given the following array: const arr = ["a", "c", "b", "c", "b"] And given an index of 4, how can we return the index of the corresponding element in ["b", "b"]? In this example, the answer is 1. More generally, how can we use the index of arr to find the corresponding index of b in arr2 where const arr2 = arr.filter(item => item === "b")? Examples: ["a", "c", "b", "c", "b"][4] corresponds to ["b", "b"][1] ["a", "c", "b", "c", "b", "b"][4] corresponds to ["b", "b", "b"][1] Inputs and expected outputs function getCorrespondingIndexInFilteredArray(array, index, filterValue) {...} getCorrespondingIndexInFilteredArray(["a", "c", "b", "c", "b"], 4, "b") // 1 getCorrespondingIndexInFilteredArray(["a", "c", "b", "c", "b", "b"], 4, "b") // 1 getCorrespondingIndexInFilteredArray(["b", "b"], 0, "b") // 0 getCorrespondingIndexInFilteredArray(["b", "b"], 1, "b") // 1 getCorrespondingIndexInFilteredArray(["a", "a"], 0, "b") // either 0 or -1 is alright here
You can use slice() upto the given index and then get the count of elements which are equal to element at given index. const arr = ["a", "b", "c", "b"] const other = (arr, ind) => { return arr.slice(0,ind).reduce((ac, a) => a === arr[ind] ? ac + 1: ac, 0); } console.log(other(arr,3)) console.log(other(arr,1))
You could use a counter object and a for loop function customIndex(arr, index) { const counter = {}; for (let i = 0; i < arr.length; i++) { counter[arr[i]] = counter[arr[i]] + 1 || 0; if (index === i) return counter[arr[i]] } return 'index out of bound' } console.log(customIndex(["a", "b", "c", "b"], 3)) console.log(customIndex(["a", "a", "b", "a"], 3)) console.log(customIndex(["a", "a", "b", "a"], 1)) You could filter the array to get the items which match arr[index] but only until index. (This will not short circuit like this first snippet) const customIndex = (arr, index) => arr.filter((n, i) => n === arr[index] && i <= index).length - 1 console.log(customIndex(["a", "b", "c", "b"], 3)) console.log(customIndex(["a", "a", "b", "a"], 3)) console.log(customIndex(["a", "a", "b", "a"], 1))
How to build a list of Arrays and convert data like [ a b c d ] to [ "a", "b", "c"]
How to build a list of Arrays and convert data like [ a b c d ] to [ "a", "b", "c"] using Javascript. I know this code does the opposite way var arr = ["a", "b", "c"]; console.log(arr.join(", "));
Assuming that the input array is an array of strings, you could write: let arr = ["a b c d", "e", "f g h"]; arr.flatMap(x => x.split(" ")); The result is ["a", "b", "c", "d", "e", "f", "g", "h"].