array.js

  1. /** @module Array */
  2. import { isFunction } from './type'
  3. /**
  4. * 获取数组的最后一个值
  5. * @function lastItem
  6. * @param {array} arr - 源数组
  7. * @return {*}
  8. * @example
  9. * let value = U.lastItem([1, 1, 2, 3])
  10. * // => 3
  11. *
  12. * let value = U.lastItem([])
  13. * // => undefined
  14. */
  15. export const lastItem = arr => arr[arr.length -1]
  16. /**
  17. * 数组去重,返回无重复值的新数组。
  18. * @function uniqueItems
  19. * @param {array} arr - 需要去重的源数组
  20. * @return {array}
  21. * @example
  22. * let arr = [1, 1, 2, 3, 3, 4, 5]
  23. * arr = U.uniqueItems(arr)
  24. * // => [1, 2, 3, 4, 5]
  25. */
  26. export const uniqueItems = arr => [...new Set(arr)]
  27. /**
  28. * 根据提供的比较器函数返回数组的所有唯一值。
  29. * @function uniqueItemsBy
  30. * @param {array} arr - 数组
  31. * @param {function} fn - 比较器函数
  32. * @param {*} fn.a - 比较元素
  33. * @param {*} fn.b - 比较元素
  34. * @param {boolean} [isRight=false] - 可选,默认false,是否从数组最后一个元素开始比较
  35. * @return {array}
  36. * @example
  37. * U.uniqueItemsBy([
  38. * { id: 0, value: 'a' },
  39. * { id: 1, value: 'b' },
  40. * { id: 2, value: 'c' },
  41. * { id: 0, value: 'd' }
  42. * ],
  43. * (a, b) => a.id == b.id)
  44. * // => [{ id: 0, value: 'a' }, { id: 1, value: 'b' }, { id: 2, value: 'c' }]
  45. *
  46. * U.uniqueItemsBy([
  47. * { id: 0, value: 'a' },
  48. * { id: 1, value: 'b' },
  49. * { id: 2, value: 'c' },
  50. * { id: 0, value: 'd' }
  51. * ],
  52. * (a, b) => a.id == b.id,
  53. * true)
  54. * // => [{ id: 0, value: 'd' }, { id: 2, value: 'c' }, { id: 1, value: 'b' }]
  55. */
  56. export const uniqueItemsBy = (arr, fn, isRight) => arr[isRight ? 'reduceRight' : 'reduce']((acc, x) => {
  57. if (!acc.some(y => fn(x, y))) acc.push(x)
  58. return acc
  59. }, [])
  60. /**
  61. * 检索数组重复元素,返回新数组。
  62. * @function repeatItems
  63. * @param {array} arr - 数组
  64. * @return {array}
  65. * @example
  66. * U.repeatItems([1, 1, 2, 3, 3, 4, 5])
  67. * // => [1, 3]
  68. */
  69. export const repeatItems = arr => arr.filter(
  70. (item, i) => (
  71. arr.indexOf(item) === i && arr.indexOf(item) !== arr.lastIndexOf(item)
  72. )
  73. )
  74. /**
  75. * 初始化一个给定长度以及值的数组。当映射是一个函数时提供迭代的i和数组长度len两个参数。
  76. * @function initArray
  77. * @param {number} len - 数组长度
  78. * @param {*|function} [val|fn=null] - 可选,数组元素的映射值,默认为null;当映射是一个函数时,该函数参数如下表:
  79. * @param {number} fn.index - 可选,数组中正在处理的当前元素的索引
  80. * @param {number} fn.length - 可选,数组的长度
  81. * @return {array}
  82. * @example
  83. * console.log(U.initArray(3))
  84. * // => [null, null, null]
  85. *
  86. * const arr = U.initArray(3, {a: 1, b: 2})
  87. * // => [ { a: 1, b: 2 }, { a: 1, b: 2 }, { a: 1, b: 2 } ]
  88. *
  89. * const arr = U.initArray(3, (i) => i * 2)
  90. * // => [ 0, 2, 4 ]
  91. */
  92. export const initArray = (len, val = null) => (
  93. isFunction(val) ? Array.from({length: len}, (item, i) => val(i, len)) : Array.from({length: len}).fill(val)
  94. )
  95. /**
  96. * 使用函数将数组的值映射到对象,其中键 - 值对由数组原始值作为键和映射值组成。
  97. * @function mapObject
  98. * @param {array} arr - 对象键名的数组
  99. * @param {function(currentValue, index, array)} fn - 生成对象值的映射函数
  100. * @param {*} fn.currentValue - 数组中正在处理的当前元素
  101. * @param {number} fn.index - 可选,数组中正在处理的当前元素的索引
  102. * @param {array} fn.array - 可选,当前正在处理的数组
  103. * @return {object}
  104. * @example
  105. * const obj = U.mapObject([1, 2, 3], i => i * 2)
  106. * // => {1: 2, 2: 4, 3: 6}
  107. */
  108. export const mapObject = (arr, fn) => {
  109. arr = [arr, arr.map(fn)]
  110. return arr[0].reduce((acc, val, i) => {
  111. acc[val] = arr[1][i]
  112. return acc
  113. }, {})
  114. }
  115. /**
  116. * 求数组内元素特定键或键映射的平均值
  117. * @function averageBy
  118. * @param {array} arr - 求值数组
  119. * @param {function|string} fn - 键值运算映射函数或键名
  120. * @return {number}
  121. * @example
  122. * const arr = [{a: 1, b: 2}, {a: 2, b: 4}]
  123. *
  124. * U.averageBy(arr, 'a')
  125. * // => 1.5
  126. *
  127. * U.averageBy(arr, o => o.a * o.b)
  128. * // => 5
  129. */
  130. export const averageBy = (arr, fn) => (
  131. arr.map(isFunction(fn) ? fn : val => val[fn]).reduce((acc, v) => acc + v, 0) / arr.length
  132. )
  133. /**
  134. * 求数组内元素特定键或键映射的最大值
  135. * @function maxBy
  136. * @param {array} arr - 求值数组
  137. * @param {function|string} fn - 键值运算映射函数或键名
  138. * @return {number}
  139. * @example
  140. * const arr = [{a: 1, b: 2}, {a: 2, b: 4}]
  141. *
  142. * U.max(arr, 'a')
  143. * // => 2
  144. *
  145. * U.maxBy(arr, o => o.a * o.b)
  146. * // => 8
  147. */
  148. export const maxBy = (arr, fn) => Math.max(...arr.map(isFunction(fn) ? fn : v => v[fn]))
  149. /**
  150. * 求数组内元素特定键或键映射的最小值
  151. * @function minBy
  152. * @param {array} arr - 求值数组
  153. * @param {function|string} fn - 键值运算映射函数或键名
  154. * @return {number}
  155. * @example
  156. * const arr = [{a: 1, b: 2}, {a: 2, b: 4}]
  157. *
  158. * U.minBy(arr, 'a')
  159. * // => 1
  160. *
  161. * U.minBy(arr, o => o.a * o.b)
  162. * // => 2
  163. */
  164. export const minBy = (arr, fn) => Math.min(...arr.map(isFunction(fn) ? fn : v => v[fn]))
  165. /**
  166. * 将数组切割分组函数
  167. * @function chunk
  168. * @param {array} arr - 切割的数组
  169. * @param {number} size - 切割数组的长度
  170. * @return {array}
  171. * @example
  172. * chunk([1, 2, 3, 4, 5], 2)
  173. * => [[1,2],[3,4],[5]]
  174. */
  175. export const chunk = (arr, size) => (
  176. Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>
  177. arr.slice(i * size, i * size + size)
  178. )
  179. )