あなたの質問にはもっと簡単な答えがあることに気付きました。私たちは、同じ名前が与えられたリスト内に複数回発生していないと仮定することができますので、これは動作します:それは、同じ名前を複数回含むことがリストのための、より正確であるため、
var simpleCombine = function (arr1, arr2) {
"use strict";
arr1 = JSON.parse(JSON.stringify(arr1));
arr2 = JSON.parse(JSON.stringify(arr2));
var i, j, arrOut = [];
while (arr1.length) {
var val = arr1.shift(), found = false;
for (j = 0; j < arr2.length; j += 1) {
if (val === arr2[j]) {
//If we wound an overlap then put everything to the left of it
// in arr2 into the final array
found = true;
var pos = arrOut.length;
arrOut.push(val);
var newVals = arr2.splice(0, j);
while (newVals.length) {
arrOut.splice(pos, 0, newVals.pop());
}
arr2.shift(); //get rid of dup
break;
}
}
if (!found) {
//No overlap found, just add it to the out array
arrOut.push(val);
}
}
//anything left in arr2? Add it to out array
arrOut = arrOut.concat(arr2);
//check for duplicates based on user requirement of each item in the
// sequence only occurs once.
for (i = 0; i < arrOut.length; i += 1) {
for (j = i + 1; j < arrOut.length; j += 1) {
if (arrOut[i] === arrOut[j]) {
//If we find an overlap warn the user, and remove the dup.
console.warn('Even with strict ordering, multiple solutions are possible');
arrOut.splice(i,1);
i -= 1;
break;
}
}
}
return arrOut;
};
var findMultipleSCS = function (arr) {
var first = arr.shift();
while (arr.length) {
first = simpleCombine(first, arr.shift());
}
return first;
};
list1 = ["Mary", "Bob", "Sue", "Roger"];
list2 = ["Bob", "Alice", "Sue", "Dave"];
list3 = ["Mary", "Bob", "Larry", "Sue", "Roger"];
console.log(findMultipleSCS([list1, list2, list3]));
私のオリジナルの答えは以下の通りです。
//This code works for things where the important thing is that order is
//maintained, not that each entry only occurs once
var findSCS = (function() {
'use strict';
var lcsLen, lcsBack, combine;
lcsLen = function(arr1, arr2) {
//This function moves through the arrays developing the
// length of the longest possible sequence of identical order.
var dists = [[0]], i, j;
for (i = 0; i < arr1.length; i += 1) {
dists[i + 1] = [];
for (j = 0; j < arr2.length; j += 1) {
dists[i + 1][0] = 0; // initialize 0'th column/row with 0
dists[0][j + 1] = 0; // this could be done in a separate loop
dists[i + 1][j + 1] = dists[i + 1][j + 1] || 0; // initialize i,j
if (arr1[i] === arr2[j]) {
//if this condition is met then we have a longer overlap
dists[i + 1][j + 1] = dists[i][j] + 1;
} else {
//if not take the max length so far
dists[i + 1][j + 1] = Math.max(dists[i][j + 1], dists[i + 1][j]);
}
}
}
return dists;
};
lcsBack = function (dists, x, y, i, j) {
//this recursive function takes the longest possible array and build
// the actual list starting from the bottom right of the matrix
// created by lcsLen
if (!i || !j) {
return [];
} else if(x[i - 1] === y[j - 1]) {
return lcsBack(dists, x, y, i - 1, j - 1).concat([x[i - 1]]);
} else {
if (dists[i][j-1] > dists[i-1][j]) {
return lcsBack(dists, x, y, i, j-1);
} else {
return lcsBack(dists,x,y,i-1,j);
}
}
};
combine = function (lcs, arr1, arr2) {
//this take the lcs and fills in the non-overlapping part of
// the original lists, creating the scs
var out = JSON.parse(JSON.stringify(arr1));
var i, testing = 0, outPos = 0, positions = [0];
for (i = 0; i < arr1.length && testing < lcs.length; i += 1) {
if (lcs[testing] === arr1[i]) {
positions[testing + 1] = i;
testing += 1;
}
}
testing = 0; outPos = 0;
for (i = 0; i < arr2.length; i += 1) {
if (lcs[testing] === undefined || lcs[testing] !== arr2[i]) {
out.splice(positions[testing] + outPos, 0, arr2[i]);
outPos += 1;
} else {
testing += 1;
outPos += 1;
}
}
return out;
};
return function (arr1, arr2) {
//get the length matrix to determine the maximum sequence overlap
var lcsLenMat = lcsLen(arr1,arr2);
//Take that distance matrix and build the actual sequence (recursively)
var lcs = lcsBack(lcsLenMat, arr1, arr2, arr1.length, arr2.length);
//Build the SCS
var tempScs = combine(lcs, arr1, arr2);
//This code will allow for duplicates, and in your second example
// It will generate a list with two bobs, which is arguably more
// correct for general purpose use.
return tempScs;
}());
var findMultipleSCS = function (arr) {
var first = arr.shift();
while (arr.length) {
first = findSCS(first, arr.shift());
}
return first;
};
list1 = ["Mary", "Bob", "Sue", "Roger"];
list2 = ["Bob", "Alice", "Sue", "Dave"];
list3 = ["Mary", "Bob", "Larry", "Sue", "Roger"];
console.log(findMultipleSCS([list1, list2, list3]));
https://en.wikipedia.org/wiki/Longest_common_subsequence_problemと
あなたが得るユニークな非どのソリューションを決定しますこれらを入れる順序から取られたこれらのアイデアのほとんどは。
["Mary", "Bob", "Larry", "Alice", "Sue", "Dave", "Roger"]
あなたはリスト1、リスト2よりも優先順位を維持したい場合は、LIST3はありませんが、独自のを持っている:インスタンスのリスト1、リスト2の場合は、LIST3はあなたの最初の答えを与える、しかしリスト2は、LIST3は、リスト1はあなたにも、正しいを与えますそれは重複を探してconsole.warnで重複している可能性を警告します。
ありがとう!これは素晴らしいスタートのように見えます。コードが配列を文字列に変換してから配列に戻す特別な理由はありますか? (少なくとも、私はそれはそれはまだそれをステップ。やっているものだと思います。)私はあなたが言及したものを固定 – jdunning
@jdunning、私は怠惰の外にいませんでした。また、各リストに各名前が1つしか含まれていないと仮定すると、はるかに効率的なアルゴリズムが見つかりました。元のアルゴリズムでは、2番目の例で[Bob、Mary、Bob、Sue]のスーパーリストが作成されます。これは、1つの名前が各リストと複数のリストの間で複数回出現することを可能にし、完全な順序を維持することにもっと重点を置くためです。 – aduss
アップデートありがとう、@aduss!私が[Mary "、" Bob "、" Sue "]、[" Bob "、" Mary "、" Sue "]という新しい関数を呼び出すと、次のような結果が得られます。"厳密な順序付けでも、 。['Mary'、 'Bob'、 'Sue'] "。とにかく、各文字列は出力オブジェクトのキーとして一度しか表示されないため、実際には私が望むものです。 – jdunning