[英]Convert array of values to array of objects (key-value) pairs in JavaScript
[英]Sorting Javascript array by comparing objects with different key-value pairs
我正在尝试对波纹管数组进行排序:
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
子条款。
PS,这是我想要的:
[
{
"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
}
]
这里有一种方法,首先为每个对象分配一个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);
由于我不知道Array.prototype.sort
的机制,我尝试了与 bubbleSort 相同的逻辑并打印步骤并找到了问题。
在每次循环开始时,bubbleSort 将未排序数组中最左边的元素作为“bubble”,并尝试将其一次向右交换一步,如果该元素小于其右邻元素,则采用右邻元素作为气泡——因此,当气泡移动到最右边时,它包含未排序元素中最大的元素。
我的问题是,我的目标集中的元素并不总是与另一个相当,所以我不能将“最大”冒泡到最右边——没有这样的“最大”。 我的目标集中的元素是“部分”可排序的:我可以在其中一些元素中设置顺序,但不是全部。
考虑到这一点,我想到了一个想法:我应该将这些可排序的元素分类成段/链,然后合并它们。 贝娄,我把它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
});
这生成了我期望的排序数组。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.