Questo può essere risolto con una Topological Sort algoritmo.
Se si considera ciascuna delle sequenze di input per essere un percorso attraverso un grafo orientato, una sorta topologico ordinerà il set di nodi da sinistra a destra in modo tale che ogni punto arco orientato verso destra.
pagina di Wikipedia su Topological Sorting include questo algoritmo, in primo luogo descritto da Arthur Kahn nel 1962:
L ← Empty list that will contain the sorted elements
S ← Set of all nodes with no incoming edges
while S is non-empty do
remove a node n from S
insert n into L
for each node m with an edge e from n to m do
remove edge e from the graph
if m has no other incoming edges then
insert m into S
if graph has edges then
return error (graph has at least one cycle)
else
return L (a topologically sorted order)
Questo algoritmo, come scritto, in realtà non fallire se trova sequenze ambigue, ma che è facile per aggiungere inserendo un controllo all'inizio del ciclo, in questo modo:
...
while S is non-empty do
if S contains more than 1 item
return error (inputs are ambiguous)
remove a node n from S
...
non so che lingua si sta lavorando, ma ho buttato insieme questa implementazione PHP come prova di concetto:
function mergeSequences($sequences, $detectAmbiguity = false) {
// build a list of nodes, with each node recording a list of all incoming edges
$nodes = array();
foreach ($sequences as $seq) {
foreach ($seq as $i => $item) {
if (!isset($nodes[$item])) $nodes[$item] = array();
if ($i !== 0) {
$nodes[$item][] = $seq[$i-1];
}
}
}
// build a list of all nodes with no incoming edges
$avail = array();
foreach ($nodes as $item => $edges) {
if (count($edges) == 0) {
$avail[] = $item;
unset($nodes[$item]);
}
}
$sorted = array();
$curr = '(start)';
while (count($avail) > 0) {
// optional: check for ambiguous sequence
if ($detectAmbiguity && count($avail) > 1) {
throw new Exception("Ambiguous sequence: {$curr} can be followed by " . join(' or ', $avail));
}
// get the next item and add it to the sorted list
$curr = array_pop($avail);
$sorted[] = $curr;
// remove all edges from the currently selected items to all others
foreach ($nodes as $item => $edges) {
$nodes[$item] = array_diff($edges, array($curr));
if (count($nodes[$item]) == 0) {
$avail[] = $item;
unset($nodes[$item]);
}
}
}
if (count($nodes) > 0) {
throw new Exception('Sequences contain conflicting information. Cannot continue after: ' . join(', ', $sorted));
}
return $sorted;
}
è possibile chiamare la funzione come questa:
$input = array(
array('XS', 'M', 'L', 'XL'),
array('S', 'M', 'XXL'),
array('XXS', 'XS', 'S', 'L'),
);
echo(join(', ', mergeSequences($input)));
echo(join(', ', mergeSequences($input, true)));
Per ottenere il seguente risultato:
XXS, XS, S, M, XXL, L, XL
Uncaught exception 'Exception' with message 'Ambiguous sequence: M can be followed by L or XXL'
Non capisco come sia possibile unire gli elenchi se le regole di precedenza sono sconosciute. –
@TylerDurden Ho modificato la domanda per renderla un po 'più chiara. Questo aiuta? – jcsanyi
No, com'è che decidi dove XXL è relativo a L e XL? –