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

时间:2019-01-23 15:06:00

标签: javascript arrays sorting

抱歉,我不知道如何制作更具描述性的标题。我正在尝试对波纹管阵列进行排序:

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
  }
]

2 个答案:

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

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