繁体   English   中英

通过比较具有不同键值对的对象来对 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM