资讯专栏INFORMATION COLUMN

JavaScript 实现数组更多的高阶函数

aervon / 2889人阅读

摘要:实现数组更多的高阶函数吾辈的博客原文场景虽说人人平等,但有些人更加平等。若是有一篇适合萌新阅读的自己实现数组更多操作的文章,情况或许会发生一些变化。类似于的初始值,但它是一个函数,避免初始值在所有分组中进行累加。

JavaScript 实现数组更多的高阶函数
吾辈的博客原文: https://blog.rxliuli.com/p/fc...
场景
虽说人人平等,但有些人更加平等。

为什么有了 Lodash 这种通用函数工具库,吾辈要写这篇文章呢?吾辈在 SegmentFault 上经常看到关于 JavaScript 数组的相关疑问,甚至于,相同类型的问题,只是数据变化了一些,就直接提出了一个新的问题(实际上,对自身并无帮助)。简单搜索了一下 Array,居然有 2360+ 条的结果,足可见这类问题的频率之高。若是有一篇适合 JavaScript 萌新阅读的自己实现数组更多操作的文章,情况或许会发生一些变化。

下面吾辈便来实现以下几种常见的操作

uniqueBy: 去重

sortBy: 排序

filterItems: 过滤掉一些元素

diffBy: 差异

groupBy: 分组

arrayToMap: Array 转换为 Map

递归操作

前言:
你至少需要了解 ES6 的一些特性你才能愉快的阅读
uniqueBy: 去重

相关问题

javascript 怎么实现多种数据类型的数组去重?

JS 有没有比较高效的数组去重的方法?

/**
 * js 的数组去重方法
 * @param arr 要进行去重的数组
 * @param kFn 唯一标识元素的方法,默认使用 {@link returnItself}
 * @returns 进行去重操作之后得到的新的数组 (原数组并未改变)
 */
function uniqueBy(arr, kFn = val => val) {
  const set = new Set()
  return arr.filter((v, ...args) => {
    const k = kFn(v, ...args)
    if (set.has(k)) {
      return false
    }
    set.add(k)
    return true
  })
}

使用

console.log(uniqueBy([1, 2, 3, "1", "2"])) // [ 1, 2, 3, "1", "2" ]
console.log(uniqueBy([1, 2, 3, "1", "2"], i => i + "")) // [ 1, 2, 3 ]
sortBy: 排序

相关问题

js 中如何对含有特殊字符的数组进行排序?

以下数组怎么按名称排序

/**
 * 快速根据指定函数对数组进行排序
 * 注: 使用递归实现,对于超大数组(其实前端的数组不可能特别大吧?#笑)可能造成堆栈溢出
 * @param arr 需要排序的数组
 * @param kFn 对数组中每个元素都产生可比较的值的函数,默认返回自身进行比较
 * @returns 排序后的新数组
 */
function sortBy(arr, kFn = v => v) {
  // TODO 此处为了让 typedoc 能生成文档而不得不加上类型
  const newArr = arr.map((v, i) => [v, i])
  function _sort(arr, fn) {
    // 边界条件,如果传入数组的值
    if (arr.length <= 1) {
      return arr
    }
    // 根据中间值对数组分治为两个数组
    const medianIndex = Math.floor(arr.length / 2)
    const medianValue = arr[medianIndex]
    const left = []
    const right = []
    for (let i = 0, len = arr.length; i < len; i++) {
      if (i === medianIndex) {
        continue
      }
      const v = arr[i]
      if (fn(v, medianValue) <= 0) {
        left.push(v)
      } else {
        right.push(v)
      }
    }
    return _sort(left, fn)
      .concat([medianValue])
      .concat(_sort(right, fn))
  }
  return _sort(newArr, ([t1, i1], [t2, i2]) => {
    const k1 = kFn(t1, i1, arr)
    const k2 = kFn(t2, i2, arr)
    if (k1 === k2) {
      return 0
    } else if (k1 < k2) {
      return -1
    } else {
      return 1
    }
  }).map(([_v, i]) => arr[i])
}

使用

console.log(sortBy([1, 3, 5, 2, 4])) // [ 1, 2, 3, 4, 5 ]
console.log(sortBy([1, 3, 5, "2", "4"])) // [ 1, "2", 3, "4", 5 ]
console.log(sortBy([1, 3, 5, "2", "4"], i => -i)) // [ 5, "4", 3, "2", 1 ]
filterItems: 过滤掉一些元素

相关问题

过滤数组子集

对比两组对象数组 根据元素内某一属性是否相等过滤数组

/**
 * 从数组中移除指定的元素
 * 注: 时间复杂度为 1~3On
 * @param arr 需要被过滤的数组
 * @param deleteItems 要过滤的元素数组
 * @param kFn 每个元素的唯一键函数
 */
function filterItems(arr, deleteItems, kFn = v => v) {
  const kSet = new Set(deleteItems.map(kFn))
  return arr.filter((v, i, arr) => !kSet.has(kFn(v, i, arr)))
}

使用

console.log(filterItems([1, 2, 3, 4, 5], [1, 2, 0])) // [ 3, 4, 5 ]
console.log(filterItems([1, 2, 3, 4, 5], ["1", "2"], i => i + "")) // [ 3, 4, 5 ]
diffBy: 差异

相关问题

JS 求两个对象数组的差集

JavaScript 数组系列问题:数组差集

/**
 * 比较两个数组的差异
 * @param left 第一个数组
 * @param right 第二个数组
 * @param kFn 每个元素的唯一标识产生函数
 * @returns 比较的差异结果
 */
function diffBy(left, right, kFn = v => v) {
  // 首先得到两个 kSet 集合用于过滤
  const kThanSet = new Set(left.map(kFn))
  const kThatSet = new Set(right.map(kFn))
  const leftUnique = left.filter((v, ...args) => !kThatSet.has(kFn(v, ...args)))
  const rightUnique = right.filter(
    (v, ...args) => !kThanSet.has(kFn(v, ...args)),
  )
  const kLeftSet = new Set(leftUnique.map(kFn))
  const common = left.filter((v, ...args) => !kLeftSet.has(kFn(v, ...args)))
  return { left: leftUnique, right: rightUnique, common }
}

使用

console.log(diffBy([1, 2, 3], [2, 3, 4])) // { left: [ 1 ], right: [ 4 ], common: [ 2, 3 ] }
console.log(diffBy([1, 2, 3], ["2", 3, 4])) // { left: [ 1, 2 ], right: [ "2", 4 ], common: [ 3 ] }
console.log(diffBy([1, 2, 3], ["2", 3, 4], i => i + "")) // { left: [ 1 ], right: [ 4 ], common: [ 2, 3 ] }
groupBy: 分组

相关问题

求一个数组按属性分组的方法

js 数组分组?

/**
 * js 数组按照某个条件进行分组
 *
 * @param arr 要进行分组的数组
 * @param kFn 元素分组的唯一标识函数
 * @param vFn 元素分组的值处理的函数。第一个参数是累计值,第二个参数是当前正在迭代的元素,如果你使用过 {@link Array#reduce} 函数的话应该对此很熟悉
 * @param init 每个分组的产生初始值的函数。类似于 reduce 的初始值,但它是一个函数,避免初始值在所有分组中进行累加。
 * @returns 元素标识 => 数组映射 Map
 */
function groupBy(
  arr,
  kFn = v => v,
  /**
   * 默认的值处理函数
   * @param res 最终 V 集合
   * @param item 当前迭代的元素
   * @returns 将当前元素合并后的最终 V 集合
   */
  vFn = (res, item) => {
    res.push(item)
    return res
  },
  init = () => [],
) {
  // 将元素按照分组条件进行分组得到一个 条件 -> 数组 的对象
  return arr.reduce((res, item, index, arr) => {
    const k = kFn(item, index, arr)
    // 如果已经有这个键了就直接追加, 否则先将之初始化再追加元素
    if (!res.has(k)) {
      res.set(k, init())
    }
    res.set(k, vFn(res.get(k), item, index, arr))
    return res
  }, new Map())
}

使用

console.log(groupBy([1, 2, 2, 2, 4, 4, 5, 5, 6], i => i)) // Map { 1 => [ 1 ],  2 => [ 2, 2, 2 ],  4 => [ 4, 4 ],  5 => [ 5, 5 ],  6 => [ 6 ] }
console.log(groupBy([1, 2, 2, 2, 4, 4, 5, 5, 6], i => i % 2 === 0)) // Map { false => [ 1, 5, 5 ], true => [ 2, 2, 2, 4, 4, 6 ] }
console.log(
  groupBy(
    [1, 2, 2, 2, 4, 4, 5, 5, 6],
    i => i % 2 === 0,
    (res, i) => res.add(i),
    () => new Set(),
  ),
) // Map { false => Set { 1, 5 }, true => Set { 2, 4, 6 } }
arrayToMap: 转换为 Map

相关问题

js 怎么把数组下面的对象里面的两个字段取出来组成一个新的对象,key:value 形式

/**
 * 将数组映射为 Map
 * @param arr 数组
 * @param k 产生 Map 元素唯一标识的函数,或者对象元素中的一个属性名
 * @param v 产生 Map 值的函数,默认为返回数组的元素,或者对象元素中的一个属性名
 * @returns 映射产生的 map 集合
 */
export function arrayToMap(arr, k, v = val => val) {
  const kFn = k instanceof Function ? k : item => Reflect.get(item, k)
  const vFn = v instanceof Function ? v : item => Reflect.get(item, v)
  return arr.reduce(
    (res, item, index, arr) =>
      res.set(kFn(item, index, arr), vFn(item, index, arr)),
    new Map(),
  )
}

使用

const county_list = [
  {
    id: 1,
    code: "110101",
    name: "东城区",
    citycode: "110100",
  },
  {
    id: 2,
    code: "110102",
    name: "西城区",
    citycode: "110100",
  },
  {
    id: 3,
    code: "110103",
    name: "崇文区",
    citycode: "110100",
  },
]
console.log(arrayToMap(county_list, "code", "name")) // Map { "110101" => "东城区", "110102" => "西城区", "110103" => "崇文区" }
console.log(arrayToMap(county_list, ({ code }) => code, ({ name }) => name)) // Map { "110101" => "东城区", "110102" => "西城区", "110103" => "崇文区" }
递归

相关问题

复杂数组去重

JavaScript 数组中包含数组如何去重?

以上种种操作皆是对一层数组进行操作,如果我们想对嵌套数组进行操作呢?例如上面这两个问题?其实问题是类似的,只是递归遍历数组而已。

/**
 * js 的数组递归去重方法
 * @param arr 要进行去重的数组
 * @param kFn 唯一标识元素的方法,默认使用 {@link returnItself},只对非数组元素生效
 * @returns 进行去重操作之后得到的新的数组 (原数组并未改变)
 */
function deepUniqueBy(arr, kFn = val => val) {
  const set = new Set()
  return arr.reduce((res, v, i, arr) => {
    if (Array.isArray(v)) {
      res.push(deepUniqueBy(v))
      return res
    }
    const k = kFn(v, i, arr)
    if (!set.has(k)) {
      set.add(k)
      res.push(v)
    }
    return res
  }, [])
}

使用

const testArr = [
  1,
  1,
  3,
  "hello",
  [3, 4, 4, "hello", "5", [5, 5, ["a", "r"]]],
  {
    key: "test",
  },
  4,
  [3, 0, 2, 3],
]
console.log(deepUniqueBy(testArr)) // [ 1,  3,  "hello",  [ 3, 4, "hello", "5", [ 5, [Object] ] ],  { key: "test" },  4,  [ 3, 0, 2 ] ]
反例

事实上,目前 SegmentFault 上存在着大量低质量且重复的问题及回答,关于这点确实比不上 StackOverflow。下面是两个例子,可以看一下能否发现什么问题

js 怎么把数组下面的对象里面的两个字段取出来组成一个新的对象,key:value 形式

JS 中处理 JSON 数据重复问题,取出里面 name 字段数值相同的作为一个数组;不相同的作为一个数组?

事实上,不管是问题还是答案,都没有突出核心 -- Array 映射为 Map/Array 分组,而且这种问题和答案还层出不穷。如果对 Array 的 API 都没有看过一遍就来询问的话,对于帮助者来说却是太失礼了!

总结

JavaScript 对函数式编程支持很好,所以习惯高阶函数于我们而言是一件好事,将问题的本质抽离出来,而不是每次都局限于某个具体的问题上。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/105360.html

相关文章

  • JavaScript 编程精解 中文第三版 五、高阶函数

    摘要:高阶函数如果一个函数操作其他函数,即将其他函数作为参数或将函数作为返回值,那么我们可以将其称为高阶函数。我们可以使用高阶函数对一系列操作和值进行抽象。高阶函数有多种表现形式。脚本数据集数据处理是高阶函数表现突出的一个领域。 来源:ApacheCN『JavaScript 编程精解 中文第三版』翻译项目原文:Higher-Order Functions 译者:飞龙 协议:CC BY-NC-...

    blastz 评论0 收藏0
  • 【重温基础】21.高阶函数

    摘要:欢迎您的支持系列目录复习资料资料整理个人整理重温基础篇重温基础对象介绍重温基础对象介绍重温基础介绍重温基础相等性判断重温基础闭包重温基础事件本章节复习的是中的高阶函数,可以提高我们的开发效率。 本文是 重温基础 系列文章的第二十一篇。 今日感受:想家。 本人自己整理的【Cute-JavaScript】资料,包含:【ES6/ES7/ES8/ES9】,【JavaScript基础...

    wua_wua2012 评论0 收藏0
  • 一文带你了解什么是JavaScript 函数式编程?

    摘要:前言函数式编程在前端已经成为了一个非常热门的话题。整个过程就是体现了函数式编程的核心思想通过函数对数据进行转换。高阶函数函数式编程倾向于复用一组通用的函数功能来处理数据,它通过使用高阶函数来实现。 前言 函数式编程在前端已经成为了一个非常热门的话题。在最近几年里,我们看到非常多的应用程序代码库里大量使用着函数式编程思想。 本文将略去那些晦涩难懂的概念介绍,重点展示在 JavaScrip...

    acrazing 评论0 收藏0
  • [前端漫谈_3] 从 filter 聊到 Promise

    摘要:前言在学习前端的时候,我总是能听到很多高级词汇,比如今天会聊到的函数式编程高阶函数。接下来我们看看,高阶函数有可能会遇到的问题,又如何去解决。 前言 在学习前端的时候,我总是能听到很多高级词汇,比如今天会聊到的 函数式编程(Functional Programming) & 高阶函数 (Higher-order function) 。但是当你真正的理解什么是 函数式编程 & 高阶函数 ...

    crossoverJie 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<