通过比较具有不同键值对的对象对Javascript数组进行排序

通过比较具有不同键值对的对象对Javascript数组进行排序,javascript,arrays,sorting,Javascript,Arrays,Sorting,我正在尝试对以下数组进行排序: var joins = [ { "joinType": "INNER JOIN", "joinTableName": "country", "joinColumnName": "id", "foreignTableName": "state", "for

我正在尝试对以下数组进行排序:

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查询语句,该表使用另一个生产系统的底层数据库中的数据定义业务对象的字段。以上部分用于创建
联接
子项

另外,我想要的是:

[
  {
    "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
  }
]

这里有一种方法,首先为每个对象分配一个
级别
,该级别由对象的根祖先的
索引
和对象所属链表中的
深度级别定义。在添加这个新的
lvl
属性之后,我们可以使用这个新属性进行排序。我不相信这种方法在性能上会有这么好的效果,但可能适合您的需要

var连接=[
{
“joinType”:“内部联接”,
“joinTableName”:“国家”,
“joinColumnName”:“id”,
“foreignTableName”:“国家”,
“foreignColumnName”:“国家/地区id”,
“索引”:1
},
{
“joinType”:“内部联接”,
“joinTableName”:“状态”,
“joinColumnName”:“id”,
“外国地名”:“城市”,
“foreignColumnName”:“state_id”,
“索引”:2
},
{
“joinType”:“内部联接”,
“joinTableName”:“城市”,
“joinColumnName”:“id”,
“foreignTableName”:“地址”,
“外国列名”:“城市id”,
“索引”:3
},
{
“joinType”:“内部联接”,
“joinTableName”:“地址”,
“joinColumnName”:“id”,
“foreignTableName”:“用户”,
“foreignColumnName”:“地址\u id”,
“索引”:4
},
{
“joinType”:“内部联接”,
“joinTableName”:“用户状态”,
“joinColumnName”:“id”,
“foreignTableName”:“用户”,
“foreignColumnName”:“状态\u id”,
“指数”:5
}
];
//查找具有外键引用的表的对象。
const findParent=(fTable)=>joins.find(x=>x.joinTableName==fTable);
//基于位置为对象指定标高的递归方法
//他们在他们所属的链表上有自己的名字。
const getLevel=(fTable,index,lvl)=>
{
让父项=findParent(fTable);
返回(fTable&父项)?
getLevel(parent.foreignTableName、parent.index、lvl+1):
指数+“-”+lvl;
}
//将输入数据映射到将标高特性添加到每个对象。
让newInput=joins.map(obj=>
{
obj.lvl=getLevel(obj.foreignTableName,obj.index,0);
返回obj;
});
//根据级别属性对新生成的数据进行排序。自从
//lvl属性是一个字符串,我们使用“localeCompare()”进行比较。
让sortedInput=newInput.sort((a,b)=>a.lvl.localeCompare(b.lvl));
//显示已排序的数据。

控制台日志(sortedInput)由于我不知道
Array.prototype.sort
的机制,我尝试了bubbleSort的相同逻辑并打印了步骤,发现了问题

在每个循环的初始阶段,bubbleSort将未排序数组中最左边的一个元素作为“bubble”,如果该元素小于它的右邻居,则尝试一次将其交换到右一步,然后将右邻域作为冒泡——因此,当冒泡位于最右边时,它包含未排序元素中最大的元素

我的问题是,我的目标集合中的元素并不总是可以与另一个元素相比较,所以我不能将“最大的”冒泡到最右边——没有这样的“最大的”。我的目标集中的元素是“部分”可排序的:我可以在其中一些元素之间设置顺序,但不能在所有元素之间设置顺序

考虑到这一点,我有了一个想法:我应该将这些可排序元素排序为段/链,然后合并它们。下面,我称之为
mergeSort
(我知道有一个著名的合并排序,但我记不起它的机制,所以我的可能与典型的合并排序不一致)


这生成了我期望的排序数组。

请同时添加所需的结果。不清楚您希望以何种顺序获取
foreignTableName
。我相信您希望在第一个if中返回-1,在第二个if中返回1。@NinaScholz--added。谢谢。您不能通过排序获得连接列表。在这种情况下,您需要采取另一种方法。请查看此问题:
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;
  }

}
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
});