For cases where the input arrays are not guaranteed to be alphabetically ordered and may contain duplicates, I've come up with the following script.
- Loop until at least one of the arrays is exhausted/consumed. It you want to use these original arrays later, make a copy or wrap my snippet in a function call.
- If both values are identical, push them into the same row in the result array.
- If not identical, determine which arrays has the closer matching value, and push all values before that match as individual rows into the result array.
- When the loop finishes, make sure to push all remaining values into the result array.
Code: (Demo)
$src = ["apple", "cherry", "grape", "lemon", "orange", "strawberry", "cherry", "cherry"];
$dst = ["apple", "banana", "cherry", "orange", "pear", "cherry"];
$result = [];
while ($src && $dst) {
if ($src[0] === $dst[0]) { // align identical values
$result[] = [array_shift($src), array_shift($dst)];
continue;
}
$earliestSrcMatch = array_search($src[0], $dst);
$earliestDstMatch = array_search($dst[0], $src);
if ($earliestSrcMatch === $earliestDstMatch) { //both false (not 0)
$result[] = [array_shift($src), null];
$result[] = [null, array_shift($dst)];
continue;
} elseif (
$earliestDstMatch === false
|| (
$earliestSrcMatch !== false
&& $earliestSrcMatch < $earliestDstMatch
)
) {
while ($dst && $src[0] !== $dst[0]) {
$result[] = [null, array_shift($dst)];
}
} elseif (
$earliestSrcMatch === false
|| $earliestSrcMatch > $earliestDstMatch
) {
while ($src && $src[0] !== $dst[0]) {
$result[] = [array_shift($src), null];
}
}
}
while ($src) {
$result[] = [array_shift($src), null];
}
while ($dst) {
$result[] = [null, array_shift($dst)];
}
To visualize as a table:
echo "<table border=1>
";
foreach ($result as $i => [$s, $d]) {
printf(
"<tr>
<td>%d</td>
<td>%s</td>
<td>%s</td>
</tr>\n",
++$i,
$s,
$d
);
}
echo "</table>";
My take on @Snor's approach would be to set up two lookup arrays so that the performance benefits of key sorting and searching can be enjoyed. On relatively large arrays, iterated calls of in_array()
may place unwanted drag on performance.
Code: (Demo)
$src = array_combine($src, $src);
$dst = array_combine($dst, $dst);
$combined_items = $src + $dst;
ksort($combined_items);
$result = [];
foreach ($combined_items as $item) {
$result[] = [
$src[$item] ?? null,
$dst[$item] ?? null
];
}