I have the following arrays:
const prev = [A, C, D, E]
const curr = [A, B, D, F]
What is the most elegant way of producing the following output?
[[A, A], [null, B], [C, null], [D, D], [E, null], [null, F]]
A, B, C, .. are objects that can be mapped on an equal field, e.g.:
A = {id: "A", ... }
The order of the final array doesn't matter.
EDIT: The two arrays are not necessarily the same length.
CodePudding user response:
Here is what I think is a solution that is easy to understand (but may not be the fastest or shortest).
- First, combine the arrays (
concat
) - While there are elements in the new list:
- Get the first element
- Use the given comparator to find the index of another element deemed the same by the comparator
- If an index was found, use the index to get the element and delete it from the list
- otherwise, it's
null
- otherwise, it's
- Add the first element and the other element to the result
It seems to work, and you can change the comparator if you want to change the criteria the output is zipped by.
const prev = ["A", "C", "D", "E"];
const curr = ["A", "B", "D", "F"];
const comparator = (a, b) => a === b; // a.id === b.id
const zip = (a, b, comparator) => {
const result = [];
const list = a.concat(b);
while (list.length) {
const element = list.shift();
const pairIndex = list.findIndex((x) => comparator(x, element));
const pair = pairIndex >= 0 ? list.splice(pairIndex, 1)[0] : null;
result.push([element, pair]);
}
return result;
};
console.log(zip(prev, curr, comparator));
CodePudding user response:
I would use this algorithm
const prev = [{ id: "A" }, { id: "C" }, { id: "D" }, { id: "E" }]
const curr = [{ id: "A" }, { id: "B" }, { id: "D" }, { id: "F" }]
const res = [];
const charCodeA = 'A'.charCodeAt(0);
let prevIndex = 0, currIndex = 0;
while (prevIndex < prev.length || currIndex < curr.length) {
const left = prev[prevIndex]?.id.charCodeAt(0) === res.length charCodeA ?
prev[prevIndex] : null;
const right = curr[currIndex]?.id.charCodeAt(0) === res.length charCodeA ?
curr[currIndex] : null;
if (left) {
prevIndex ;
}
if (right) {
currIndex ;
}
res.push([left, right])
}
console.log(res)
CodePudding user response:
Use set operations to find all the values that are in common between the two arrays, only in the first array, and only in the second array. Then create the appropriate pairs for each group.
const prev = ['A', 'C', 'D', 'E'];
const curr = ['A', 'B', 'D', 'F'];
const prevSet = new Set(prev);
const currSet = new Set(curr);
const intersection = prev.filter(el => currSet.has(el));
const only_prev = prev.filter(el => !currSet.has(el));
const only_curr = curr.filter(el => !prevSet.has(el));
let result = intersection.map(el => [el, el]);
result = result.concat(only_prev.map(el => [el, null]));
result = result.concat(only_curr.map(el => [null, el]));
console.log(result);
CodePudding user response:
Iterate the first one and populate the hash value => [value,null]
. Iterate the second one, if value is in the hash, replace null
with the value, otherwise add [null, value]
:
const prev = ['A','C','D','E']
const curr = ['A','B','D','F']
let m = {}
for (let a of prev)
m[a] = [a, null]
for (let a of curr)
if (a in m)
m[a][1] = a
else
m[a] = [null, a]
console.log(...Object.values(m))
CodePudding user response:
Maybe try something more generic like this:
function zip(lists = []) {
const joined = lists.flatMap(list => list); // Put all elements in a single list
const set = new Set(joined); // Create a set to only have distinct elements
const items = [...set]; // Convert the set to a list
items.sort() // Sort the list
const result = []; // Create the result array
items.forEach(item => {
const zippedItem = []; // Create the zip line
lists.forEach(list => {
if (list.includes(item)) zippedItem.push(item); // only push the item if is present in one of the original arrays
else zippedItem.push(null); // Otherwise push a null value
});
result.push(zippedItem); // Push the zipped item to the result array
})
return result; // Return the zipped values
}
Use the function like this:
const prev = ['A', 'C', 'D', 'E'];
const curr = ['A', 'B', 'D', 'F'];
const zipped = zip([prev, curr]);
This will produce this result;
[
[ 'A', 'A' ],
[ null, 'B' ],
[ 'C', null ],
[ 'D', 'D' ],
[ 'E', null ],
[ null, 'F' ]
]