Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
wingmeng opened this issue May 8, 2019 · 4 comments
Open

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

wingmeng opened this issue May 8, 2019 · 4 comments

Comments

@wingmeng
Copy link
Collaborator

wingmeng commented May 8, 2019

这是前端晚练课的第 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

@liwenkang
Copy link

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')

@cnyballk
Copy link

cnyballk commented May 8, 2019

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

@limoning
Copy link

limoning commented May 9, 2019

/**
 * 多重排序
 * @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]]
    }
  })
}

@ahao430
Copy link

ahao430 commented May 9, 2019

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
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants