Visitar URL original
第 1 期(2019-05-08):多重排序 · Issue #2 · fezaoduke/fe-practice-hard · GitHub
Skip to content

第 1 期(2019-05-08):多重排序 #2

Description

@wingmeng

这是前端晚练课的第 1 期,希望大家在参与前先去「达成以下 2 个成就」:

  1. 有看过 「前端晚练课的简介、愿景、角色、参与方式和激励措施」
  2. 有阅读过 「答题规范」

来源:原创题
难度:★★

封装一个多重排序函数 multiSort,功能要求:

  1. 接收一个对象数组,返回一个按多个字段名顺序排序后的新数组;
  2. 可自定义排序参照的字段名顺序;

例如:['field2', 'field1', 'field3']

首先按 field2 进行排序,如果 field2 的值相等,则按 field1 排序;如果 field1 的值仍相等,则按 field3 排序……

  1. 可设置排序规则为正序(升序)或倒序(降序),默认为正序。

实战用例:

根据员工数据,评选出月度最佳员工

[
  { "name": "Sweet", "education": 4, "sales": 10, "duty": 24, "workAge": 2 },
  { "name": "Tough", "education": 3, "sales": 15, "duty": 24, "workAge": 6 },
  { "name": "Yummy", "education": 4, "sales": 10, "duty": 24, "workAge": 4 },
  { "name": "Ghost", "education": 6, "sales": 15, "duty": 23, "workAge": 8 },
  { "name": "Flora", "education": 5, "sales": 15, "duty": 24, "workAge": 6 }
]

按 销售额(sales)、出勤天数(duty)、工龄(workAge)、教育程度(education) 的顺序 降序 排名:

[
  { "name": "Flora", "education": 5, "sales": 15, "duty": 24, "workAge": 6 },
  { "name": "Tough", "education": 3, "sales": 15, "duty": 24, "workAge": 6 },
  { "name": "Ghost", "education": 6, "sales": 15, "duty": 23, "workAge": 8 },
  { "name": "Yummy", "education": 4, "sales": 10, "duty": 24, "workAge": 4 },
  { "name": "Sweet", "education": 4, "sales": 10, "duty": 24, "workAge": 2 }
]

参考答案:

function multiSort(arr, rules, reversal) {
  return [...arr].sort((o, p) => {
    let a, b;

    for (let rule of rules) {
      a = o[rule];
      b = p[rule];

      if (a !== b) {
        return (a - b) * (reversal ? -1 : 1);
      }
    }
  });
}

// 或者挂载到 Array 构造函数的原型上
Array.prototype.multiSort = function(rules, reversal) {
  return [...this].sort((o, p) => {
    // 逻辑代码同上,此处略
  });
}

本期优秀回答者: @cnyballk

Activity

  1. liwenkang commented on May 8, 2019

    @liwenkang
    var list = [
        {"name": "Sweet", "education": 4, "sales": 10, "duty": 24, "workAge": 2},
        {"name": "Tough", "education": 3, "sales": 15, "duty": 24, "workAge": 6},
        {"name": "Yummy", "education": 4, "sales": 10, "duty": 24, "workAge": 4},
        {"name": "Ghost", "education": 6, "sales": 15, "duty": 23, "workAge": 8},
        {"name": "Flora", "education": 5, "sales": 15, "duty": 24, "workAge": 6}
    ]
    
    var fieldArray = ['sales', 'duty', 'workAge', 'education']
    
    function multiSort(data, fieldArray, sortMethod = 'ascendingOrder') {
        // 为了不修改原数组,使用了 data.slice()
        return data.slice().sort((a, b) => {
            for (var i = 0; i < fieldArray.length; i++) {
                if (b[fieldArray[i]] !== a[fieldArray[i]]) {
                    if (sortMethod === 'descendingOrder') {
                        // 降序
                        return b[fieldArray[i]] - a[fieldArray[i]]
                    } else if (sortMethod === 'ascendingOrder') {
                        // 升序
                        return a[fieldArray[i]] - b[fieldArray[i]]
                    }
                }
            }
        })
    }
    
    multiSort(list, fieldArray, 'descendingOrder')
  2. cnyballk commented on May 8, 2019

    @cnyballk
    const multiSort = (dataSource=[], filters=[], invertedOrder = false) =>
      [...dataSource].sort((a, b) => {
        for (let i of filters) {
          if (a[i] !== b[i]) {
            return invertedOrder ? a[i] < b[i] : a[i] > b[i];
          }
        }
      });
  3. limoning commented on May 9, 2019

    @limoning
    /**
     * 多重排序
     * @param {Array} arr 要排序的数组
     * @param {Array} sortField 排序字段 
     * @param {Boolean} isAscending 是否升序 默认为是
     */
    const multiSort = (arr, sortField, isAscending = true) => {
      // 如果没有排序字段直接返回原数组顺序的新数组
      if (!sortField || !sortField.length) {
        return [...arr]
      }
      const len = sortField.length
      return [...arr].sort((obj1, obj2) => {
        let index = 0
        // 循坏找出一个不相等的排序字段的下标
        while (obj1[sortField[index]] === obj2[sortField[index]] && index < len) {
          index++
        }
        // 如果下标等于排序字段数组长度则表示所有字段都相等直接返回0
        if (index === len) {
          return 0
        } else {
          return isAscending
            ? obj1[sortField[index]] - obj2[sortField[index]]
            : obj2[sortField[index]] - obj1[sortField[index]]
        }
      })
    }
  4. ahao430 commented on May 9, 2019

    @ahao430
    const multiSort = (data, conditions, order = 'asc') => {
      let len = conditions.length
      const getOrder = (a, b, index) => {
        let condition = conditions[index]
        if (a[condition] === b[condition] && index < len - 1) {
          return getOrder(a, b, index + 1)
        } else {
          return order === 'desc' ? b[condition] - a[condition] : a[condition] - b[condition]
        }
      }
    
      return data.sort((a, b) => {
        return getOrder(a, b, 0)
      })
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions