抱歉,我不知道如何制作更具描述性的标题。我正在尝试对波纹管阵列进行排序:
var joins = [
{
"joinType": "INNER JOIN",
"joinTableName": "country",
"joinColumnName": "id",
"foreignTableName": "state",
"foreignColumnName": "country_id",
"index": 1
},
{
"joinType": "INNER JOIN",
"joinTableName": "state",
"joinColumnName": "id",
"foreignTableName": "city",
"foreignColumnName": "state_id",
"index": 2
},
{
"joinType": "INNER JOIN",
"joinTableName": "city",
"joinColumnName": "id",
"foreignTableName": "address",
"foreignColumnName": "city_id",
"index": 3
},
{
"joinType": "INNER JOIN",
"joinTableName": "address",
"joinColumnName": "id",
"foreignTableName": "user",
"foreignColumnName": "address_id",
"index": 4
},
{
"joinType": "INNER JOIN",
"joinTableName": "user_status",
"joinColumnName": "id",
"foreignTableName": "user",
"foreignColumnName": "status_id",
"index": 5
}
]
使用以下代码:
joins.sort((a, b) => {
if (a.foreignTableName === b.joinTableName) return 1; //b comes first
else if (a.joinTableName === b.foreignTableName) return -1; //a comes first
else return 0; //no change
});
结果是:
[
{
"joinType": "INNER JOIN",
"joinTableName": "state",
"joinColumnName": "id",
"foreignTableName": "city",
"foreignColumnName": "state_id",
"index": 2
},
{
"joinType": "INNER JOIN",
"joinTableName": "country",
"joinColumnName": "id",
"foreignTableName": "state",
"foreignColumnName": "country_id",
"index": 1
},
{
"joinType": "INNER JOIN",
"joinTableName": "address",
"joinColumnName": "id",
"foreignTableName": "user",
"foreignColumnName": "address_id",
"index": 4
},
{
"joinType": "INNER JOIN",
"joinTableName": "city",
"joinColumnName": "id",
"foreignTableName": "address",
"foreignColumnName": "city_id",
"index": 3
},
{
"joinType": "INNER JOIN",
"joinTableName": "user_status",
"joinColumnName": "id",
"foreignTableName": "user",
"foreignColumnName": "status_id",
"index": 5
}
]
这不是我期望的-我希望索引2和1的元素位于索引3的元素之后。
要添加更多详细信息,这是用于从对象字段定义表创建MySql查询语句,该表使用另一个生产系统的底层DB中的数据来定义业务对象的字段。上面的部分是用于创建JOIN
子句的。
P.S。,这就是我想要的:
[
{
"joinType": "INNER JOIN",
"joinTableName": "address",
"joinColumnName": "id",
"foreignTableName": "user",
"foreignColumnName": "address_id",
"index": 4
},
{
"joinType": "INNER JOIN",
"joinTableName": "city",
"joinColumnName": "id",
"foreignTableName": "address",
"foreignColumnName": "city_id",
"index": 3
},
{
"joinType": "INNER JOIN",
"joinTableName": "state",
"joinColumnName": "id",
"foreignTableName": "city",
"foreignColumnName": "state_id",
"index": 2
},
{
"joinType": "INNER JOIN",
"joinTableName": "country",
"joinColumnName": "id",
"foreignTableName": "state",
"foreignColumnName": "country_id",
"index": 1
},
{
"joinType": "INNER JOIN",
"joinTableName": "user_status",
"joinColumnName": "id",
"foreignTableName": "user",
"foreignColumnName": "status_id",
"index": 5
}
]
答案 0 :(得分:1)
这里有一种方法,首先为每个对象分配一个level
,级别由一个对象的根祖先的index
和该对象是level of deep
来定义在它所属的链表中。添加此新的lvl
属性后,我们可以使用此新属性进行排序。我认为这种方法的性能不会很好,但是也许可以满足您的需求。
var joins = [
{
"joinType": "INNER JOIN",
"joinTableName": "country",
"joinColumnName": "id",
"foreignTableName": "state",
"foreignColumnName": "country_id",
"index": 1
},
{
"joinType": "INNER JOIN",
"joinTableName": "state",
"joinColumnName": "id",
"foreignTableName": "city",
"foreignColumnName": "state_id",
"index": 2
},
{
"joinType": "INNER JOIN",
"joinTableName": "city",
"joinColumnName": "id",
"foreignTableName": "address",
"foreignColumnName": "city_id",
"index": 3
},
{
"joinType": "INNER JOIN",
"joinTableName": "address",
"joinColumnName": "id",
"foreignTableName": "user",
"foreignColumnName": "address_id",
"index": 4
},
{
"joinType": "INNER JOIN",
"joinTableName": "user_status",
"joinColumnName": "id",
"foreignTableName": "user",
"foreignColumnName": "status_id",
"index": 5
}
];
// Find the object with the table a foreign key is referencing.
const findParent = (fTable) => joins.find(x => x.joinTableName === fTable);
// Recursive method that assigns a level to an object based on the position
// they have on the linked list they belong to.
const getLevel = (fTable, index, lvl) =>
{
let parent = findParent(fTable);
return (fTable && parent) ?
getLevel(parent.foreignTableName, parent.index, lvl + 1) :
index + "-" + lvl;
}
// Maps the input data to adds the level property to each object.
let newInput = joins.map(obj =>
{
obj.lvl = getLevel(obj.foreignTableName, obj.index, 0);
return obj;
});
// Sorts the new generated data based on the level property. Since the
// lvl property is a string, we use "localeCompare()" to compare.
let sortedInput = newInput.sort((a, b) => a.lvl.localeCompare(b.lvl));
// Shows the sorted data.
console.log(sortedInput);
答案 1 :(得分:0)
由于我不了解Array.prototype.sort
的机制,因此我使用bubbleSort尝试了相同的逻辑,并打印了步骤并发现了问题。
在每个循环的开始,bubbleSort会将未排序数组中最左边的元素作为“气泡”,并尝试一次将其向右交换一次(如果该元素小于它的右邻居),然后将右边的邻居作为气泡-因此,当气泡移到最右边时,它包含未排序元素中最大的一个。
我的问题是,目标集中的元素并不总是可以与另一个元素进行比较,因此我无法将“最大”气泡到最右边-没有这样的“最大”。目标集中的元素是“部分”可排序的:我可以在其中一些(但不是全部)中设置订单。
考虑到这一点,我想到了一个主意:我应该将这些可排序元素分类为段/链,然后将它们合并。贝娄,我称之为mergeSort
(我知道有一个著名的合并排序,但我不记得它的机制,因此我的可能与典型的合并排序不一致)。
function mergeSort(arr, compFn) {
let res = [];
while (arr.length > 0) {
res = res.concat(makeChain(arr.splice(0, 1)[0], compFn));
}
return res.filter(n => n);
function makeChain(obj, compFn) {
let res = [obj];
for (let i = 0; i < arr.length; i++) {
if (isEmpty(arr[i])) return;
let flag = compFn(obj, arr[i]);
if (flag < 0) {
res = res.concat(makeChain(arr.splice(i, 1)[0], compFn));
} else if (flag > 0) {
res = makeChain(arr.splice(i, 1)[0], compFn).concat(res);
}
}
return res;
}
}
然后我仍然可以使用相同的compareFunction:
joins = mergeSort(joins, (a, b) => {
if (a.foreignTableName === b.joinTableName) return 1; //b comes first
else if (a.joinTableName === b.foreignTableName) return -1; //a comes first
else return 0; //no change
});
这会生成我期望的排序数组。