前言
- 前篇我们已经介绍了 radash 的相关信息和部分 Array 相关方法,详情可前往主页查看;
- 本篇我们继续介绍 radash 中 Array 的其他相关方法;
Radash 的 Array 相关方法详解
first:获取数组第一项,不存在返回默认值
- 使用说明
- 参数:目标数组,或者传递两个参数空数组和默认值;
- 返回值:传目标数组则返回目标数组的第一项,传空数组和默认值则返回默认值。
- 使用代码示例
import { first } from 'radash' const gods = ['lufee', 'loki', 'zeus'] first(gods) // => 'lufee' first([], 'zuoluo') // => 'zuoluo'
- 源码解析
// 定义一个泛型函数 `first`,它接收一个具有只读属性的泛型数组 `array`, // 和一个可选的默认值 `defaultValue`,其类型可以是泛型 `T` 或 `null` 或 `undefined`,默认值为 `undefined`。 export const first = <T>( array: readonly T[], defaultValue: T | null | undefined = undefined ) => { // 如果数组存在且长度大于0,返回数组的第一个元素。 // 否则,返回提供的默认值 `defaultValue`。 return array?.length > 0 ? array[0] : defaultValue }
-
方法流程说明:
- 检查传入的数组
array是否存在并且长度是否大于0。 - 如果数组存在且不为空(长度大于0),则返回数组的第一个元素
array[0]。 - 如果数组不存在或为空,返回
defaultValue。
这个函数对于需要安全地访问数组第一个元素而不抛出错误的情况很有用,特别是在不确定数组是否为空的情况下。通过提供一个默认值,你可以避免在数组为空时访问未定义的索引。如果没有提供默认值,函数将默认返回
undefined。 - 检查传入的数组
flat:数组扁平化 —— 把包含多个数组的数组转为一个数组(注意不会递归)
- 使用说明
- 参数:包含多个数组的数组;
- 返回值:降低一维后的数组;
- 注意:不会递归降维,只能降一维。
- 使用代码示例
import { flat } from 'radash' const gods = [['shy', 'ning'], ['jkl']] flat(gods) // => [shy, ning, jkl]
- 源码解析
// 定义一个泛型函数 `flat`,它接收一个具有只读属性的二维泛型数组 `lists`, // 并返回一个扁平化的一维数组。 export const flat = <T>(lists: readonly T[][]): T[] => { // 使用数组的 `reduce` 方法来累积(合并)所有子数组的元素。 return lists.reduce((acc, list) => { // 使用 `push` 方法的展开语法(...)将当前处理的子数组 `list` 的所有元素添加到累加器 `acc` 中。 acc.push(...list) // 返回更新后的累加器 `acc`,以便它可以在下一次迭代中使用。 return acc }, []) // 初始化累加器 `acc` 为一个空数组。 }
- 方法流程说明:
- 使用
reduce方法遍历二维数组lists。reduce方法的累加器acc是一个一维数组,用于收集所有子数组的元素。 - 对于
lists中的每个子数组list,使用展开语法...将其元素添加到累加器数组acc中。 - 每次迭代结束后,返回更新的累加器
acc。 - 当
reduce方法完成遍历后,返回最终的累加器acc,这时它包含了lists中所有子数组的元素,形成了一个扁平化的一维数组。 - 提示:这个
flat函数在功能上类似于 Array.prototype.flat 方法,但是它是手动实现的,适用于不支持内建flat方法的环境。
- 使用
fork:按条件将数组拆分成两个数组,满足条件的一个,不满足条件的一个
- 使用说明
- 参数:目标数组,条件函数;
- 返回值:返回两个数组,一个保存满足条件的项,另一个保存不满足条件的项。
- 使用代码示例
import { fork } from 'radash' const gods = [ { name: 'Uzi', power: 100 }, { name: 'Xiaohu', power: 98 }, { name: 'Ming', power: 72 }, { name: 'Mlxg', power: 100 } ] const [finalGods, lesserGods] = fork(gods, f => f.power > 90) // [[Uzi, Xiaohu, Mlxg], [Ming]]
- 源码解析
// 定义一个泛型函数 `fork`,它接受一个具有只读属性的泛型数组 `list`, // 和一个条件函数 `condition`,根据此函数将 `list` 中的元素分成两组。 export const fork = <T>( list: readonly T[], condition: (item: T) => boolean ): [T[], T[]] => { // 如果传入的 `list` 为空,则返回两个空数组。 if (!list) return [[], []] // 使用数组的 `reduce` 方法来累积分离出的两个子数组。 return list.reduce( (acc, item) => { // 从累加器中解构出两个子数组 a 和 b。 const [a, b] = acc // 如果当前元素 `item` 满足条件函数 `condition`,将其添加到数组 a,否则添加到数组 b。 if (condition(item)) { return [[...a, item], b] } else { return [a, [...b, item]] } }, [[], []] as [T[], T[]] // 初始化累加器为两个空数组。 ) }
- 方法流程说明:
- 首先检查传入的数组
list是否为空。如果为空,返回一对空数组。 - 使用
reduce方法遍历list数组。reduce方法的累加器acc是一个包含两个子数组的元组[T[], T[]]。 - 对于
list中的每个元素item,检查它是否满足条件函数condition。 - 如果条件函数返回
true,则将该元素添加到累加器的第一个子数组a。如果条件函数返回false,则将该元素添加到第二个子数组b。 - 在每次迭代结束后,返回更新后的累加器
[a, b]。 - 当
reduce方法完成遍历后,返回最终的累加器[a, b],它包含了根据条件函数分离的两个子数组。
- 首先检查传入的数组
group:根据条件函数指定的key构建一个统计对象,key 为指定的 key 有哪些 value ,value 为对应对象
- 使用说明
- 参数:对象数组、条件函数;
- 返回值:统计对象
- 使用代码示例
import { group } from 'radash' const fish = [ { name: 'Marlin', source: 'ocean' }, { name: 'Bass', source: 'lake' }, { name: 'Trout', source: 'lake' } ] const fishBySource = group(fish, f => f.source) // => { ocean: [marlin], lake: [bass, trout] }
- 源码解析
// 定义一个泛型函数 `group`,它接受一个具有只读属性的泛型数组 `array`, // 和一个函数 `getGroupId`,该函数用于从数组元素中提取一个标识符作为组的键。 export const group = <T, Key extends string | number | symbol>( array: readonly T[], getGroupId: (item: T) => Key // 返回一个对象,其键是通过 `getGroupId` 函数提取的标识符,键对应的值是具有相同标识符的元素数组。 ): Partial<Record<Key, T[]>> => { // 使用数组的 `reduce` 方法来累积分组结果。 return array.reduce((acc, item) => { // 使用 `getGroupId` 函数从当前元素 `item` 中获取组标识符 `groupId`。 const groupId = getGroupId(item) // 如果累加器 `acc` 中还没有这个组标识符的键,初始化为一个空数组。 if (!acc[groupId]) acc[groupId] = [] // 将当前元素 `item` 添加到对应组标识符的数组中。 acc[groupId].push(item) // 返回更新后的累加器 `acc`,以便它可以在下一次迭代中使用。 return acc }, {} as Record<Key, T[]>) // 初始化累加器为一个空对象。 }
- 方法流程说明:
- 遍历传入的数组
array,对每个元素使用getGroupId函数来确定它应该属于哪个组。 - 对于每个元素,检查累加器
acc(一个对象)中是否已经有一个数组存在于以groupId为键的位置。如果没有,就在那个位置创建一个空数组。 - 将当前元素
item添加到acc[groupId]数组中。 - 继续处理数组的下一个元素,直到所有元素都被处理完毕。
- 返回累加器
acc,它现在包含了按groupId分组的元素数组。 - tips:在TypeScript中,
Partial<Record<Key, T[]>>是一种类型,它表示一个对象,这个对象的键可以是Key类型,而每个键对应的值是T[]类型的数组。Partial和Record都是TypeScript中的高级类型。
- 遍历传入的数组
intersects:判断两个数组是否有公共项,返回一个布尔值
- 使用说明
- 参数:数组1,数组2,可选条件函数(用于提取随机标识符,对对象数组进行操作时);
- 返回值:有返回true,否则返回false。
- 使用代码示例
import { intersects } from 'radash' const oceanFish = ['tuna', 'tarpon'] const lakeFish = ['bass', 'trout'] intersects(oceanFish, lakeFish) // => false const brackishFish = ['tarpon', 'snook'] intersects(oceanFish, brackishFish) // => true
- 源码解析
// 定义一个泛型函数 `intersects`,它接受两个具有只读属性的泛型数组 `listA` 和 `listB`, // 以及一个可选的函数 `identity`,用于从数组元素中提取一个唯一标识符。 export const intersects = <T, K extends string | number | symbol>( listA: readonly T[], listB: readonly T[], identity?: (t: T) => K ): boolean => { // 如果 `listA` 或 `listB` 不存在,返回 false。 if (!listA || !listB) return false // 如果 `identity` 函数未提供,则使用默认函数,它将元素作为其自己的标识符。 const ident = identity ?? ((x: T) => x as unknown as K) // 使用 `listB` 的元素创建一个记录对象 `dictB`,键是通过 `ident` 函数提取的唯一标识符,值为 `true`。 const dictB = listB.reduce((acc, item) => { acc[ident(item)] = true return acc }, {} as Record<string | number | symbol, boolean>) // 检查 `listA` 中是否有元素的唯一标识符存在于 `dictB` 中。 return listA.some(value => dictB[ident(value)]) }
- 方法流程说明:
- 检查传入的数组
listA和listB是否存在。如果任何一个不存在,返回false。 - 如果未提供
identity函数,则使用一个默认函数,它将每个元素x强制转换为K类型,作为其唯一标识符。 - 遍历数组
listB,使用reduce方法和ident函数将其元素映射到一个记录对象dictB中,其中键是元素的唯一标识符,值为true。 - 使用
some方法检查数组listA中是否有任何元素的唯一标识符存在于dictB中。如果存在,some方法会返回true,表示两个数组有交集。 - 如果
listA中没有任何元素的唯一标识符在dictB中找到,some方法返回false,表示两个数组没有交集。 - 提示:
??表示 TypeScript 中的空值合并运算符 。这个运算符用于提供一个默认值,当左侧的操作数identity是null或undefined时,就会使用右侧的操作数作为默认值。x as unknown as K是 Typescript 的类型断言。
- 检查传入的数组
下期我们将介绍以下方法
- iterate:把一个函数迭代执行指定次数;
- last:输出数组的最后一项,如果数组为空则输出传入的默认值;
- list:创建包含特定项的数组;
- max:获取对象数组中指定标识符最大的项;
- merge:合并数组,并且会覆盖第一个数组;
- min:获取对象数组中指定标识符最小的项;
- objectify:根据函数映射的键与值把数组转换为字典对象;
- range:根据步长生成一个数值范围内的迭代值;
- replaceOrAppend:替换对象数组中的项或是追加项(条件函数不满足时追加);
- replace:替换数组中的第一个匹配项。
写在后面
- 后续作者会整理一份方法目录上传,方便没法访问外网的朋友查看使用。
- 该系列会在每周五更新,遇节假日提前。
- 大家有任何问题或者见解,欢迎评论区留言交流!!!
- 点击访问:radash 官网