这是我今天遇到的一项有趣的任务,我想不出任何简单的方法来达到预期的效果。
假设我们有一个包含以下字段(列)的数据库: A,B,C,D,E,F,G 但我们不知道名称和计数字段。
我们会按以下格式从此数据库中收到一组记录: {A:value1,B:value2,...} 。
如果没有为当前记录设置值,则该键也将丢失。这意味着我可以将 {A:value} 或 {C:value1,D:value2} 作为有效记录。键的顺序将始终保持不变。这意味着 {D:value,C:value} 不是有效记录。
我正在尝试根据返回的记录恢复字段名称并保持密钥的顺序。
例如,我可以使用以下键接收记录:
从上面的例子中我应该能够恢复原来的序列 A,B,C,D,E,F,G 。
如果订单无法确定,我们可以使用字母顺序。例如:
在上面的示例中,我们无法确定原始订单是 A,B,C 还是 A,C,B 。
任何想法如何实现这一点在一般情况下工作?
我将使用 JavaScript 实现此算法,但 PHP , C ++ 或 Java 也是受欢迎的。< / p>
编辑:不要将对象视为标准JSON对象。在真实环境中,结构要复杂得多,语言不是纯粹的 JavaScript ,而是 ECMAScript 的修改版本。如果它更容易理解 - 只考虑键作为一组值 ['A','B','C',...] 并尝试合并它们,保持顺序。
编辑2:经过一段时间的努力并阅读了一些想法后,我提出了以下解决方案:
您可以在下面找到附带的源代码:
var allComparators = {};
var knownObjects = ['A,C,D,E,F','D,F,G','A,B,F'];
var allFields = knownObjects.join(',').split(',');
for (var i in knownObjects) {
var arr = knownObjects[i].split(',');
for (var i = 0; i < arr.length; i++) {
for (var j = i + 1; j < arr.length; j++) {
allComparators[arr[i]+'_'+arr[j]] = 1;
}
}
}
allFields = allFields.filter(function(value, index, self) {
return self.indexOf(value) === index;
});
for (var i in allFields) {
for (var j in allFields) {
for (var k in allFields) {
if (allComparators[allFields[i]+'_'+allFields[j]] && allComparators[allFields[j]+'_'+allFields[k]]) {
allComparators[allFields[i]+'_'+allFields[k]] = 1;
}
}
}
}
allFields.sort(function(a, b) {
if (typeof allComparators[a + '_' + b] != 'undefined') {
return -1;
}
if (typeof allComparators[b + '_' + a] != 'undefined') {
return 1;
}
return a > b;
});
console.log(allFields);
答案 0 :(得分:1)
我以非常直接且易于理解的方式为您提供算法但代码!如果需要,请尝试自己并寻求帮助。 我用两种方式表达自己
技术术语:
更多细节:
图形:Map(String,ArrayList&lt; String&gt;)= [Map(key,value)]
地图中的每个键对应一个元素(A,B,C,......)
每个值包含应放在键后面的元素,例如A,它是{B,C,D,...}
如何填写图表:
for each row: for each element inside the row: if the element is already as a key in the map just add its immediate next item to the list* else add the element to the map and set the value to immediate next element of it**
*
如果元素是行中的最后一个元素,则不向地图添加任何内容
**
如果元素是行中的最后一个,则使用{},一个空列表,作为值
拓扑排序:
List sortedList; for each key in the map: if value.size() == 0 { remove key from the map add it the key to the sortedList for each key' in the map: if value'.contains(key) value'.remove(key) (and update the map) } invert the sortedList
测试用例:
the map for your first input will be: { A:{C,B} , C:{D} , D:{E,F} , E:{F} , F:{G} , G:{} , B:{F} } Sort : 1 - G -> sortedList, map = { A:{C,B} , C:{D} , D:{E,F} , E:{F} , F:{} , B:{F} } 2 - F -> sortedList, map = { A:{C,B} , C:{D} , D:{E} , E:{} , B:{} } 3 - E -> sortedList, map = { A:{C,B} , C:{D} , D:{} } 4 - D -> sortedList, map = { A:{C,B} , C:{} } 5 - C -> sortedList, map = { A:{B} , B:{} } 6 - B -> sortedList, map = { A:{} } 6 - A -> sortedList, map = { } sortedList = {G,F,E,D,C,B,A} Invert - > {A,B,C,D,E,F,G}
答案 1 :(得分:1)
var oMergedList = [];
function indexOfColumn(sColumnName)
{
for(var i = 0 ; i < oMergedList.length;i++)
if(oMergedList[i]==sColumnName)
return i;
return -1;
}
function getOrdinalIndex(sColumnName)
{
var i = 0;
for( ; i < oMergedList.length;i++)
if(oMergedList[i]>sColumnName)
break;
return i;
}
function merge(oPartial)
{
var nPreviousColumnPosition = -1;
for(var i = 0 ; i < oPartial.length;i++)
{
var sColumnName = oPartial[i] ;
var nColumnPosition = indexOfColumn(sColumnName);
if(nColumnPosition>=0)//already contained
{
if(nPreviousColumnPosition>=0 && nColumnPosition!=(nPreviousColumnPosition+1))//but inserted on wrong place
{
oMergedList.splice(nColumnPosition, 1);
nColumnPosition = nPreviousColumnPosition
oMergedList.splice(nColumnPosition, 0, sColumnName);
}
nPreviousColumnPosition = nColumnPosition;
}
else //new
{
if(nPreviousColumnPosition<0)//no reference column
{
nPreviousColumnPosition = getOrdinalIndex(sColumnName);
}
else// insert after previous column
nPreviousColumnPosition++;
oMergedList.splice(nPreviousColumnPosition, 0, sColumnName);
}
}
}
/* latest sample
merge(['A','C','E','G']);
merge(['A','D']);
merge(['C','D']);
*/
/* default sample
merge(['A','C','D','E','F']);
merge(['D','F','G']);
merge(['A','B','F']);
*/
/* fix order
merge(['A','B']);
merge(['A','C']);
merge(['A','B','C']);
*/
/* insert alphabetically
merge(['B']);
merge(['A']);
merge(['C']);
*/
document.body.innerHTML = oMergedList.join(',');
唯一的“未定义”部分是在没有先前列的情况下插入的位置(我把它放在第一位) 第二个在案例A,B .. A,C中,第一次看到时会插入列
表示A,B..A,C表示A,C,B ..表示A,C..A,B表示A,B,C
编辑以使用当前数组位置进行修复 之前的添加所以如果你添加[A,C] [A,B]你会得到[A,C,B],但如果你再通过[A,B,C] 数组将被修复以反映新订单
当新列出现且没有参考列按字母顺序添加时
修正了列修正标准..现在应该给你正确的结果..
答案 2 :(得分:0)
正如JSON.org所描述的那样,没有Json订购的密钥:
对象是一组无序的名称/值对。
话虽如此,合并对象变得非常容易,因为您不需要订单。
for (var attrname in obj2) { obj1[attrname] = obj2[attrname]; }
来源:How can I merge properties of two JavaScript objects dynamically?