前言

  • 前篇我们已经介绍了 radash 的相关信息和部分 Array 相关方法,详情可前往主页查看;
  • 本篇我们继续介绍 radash 中 Array 的其他相关方法;

Radash 的 Array 相关方法详解

first:获取数组第一项,不存在返回默认值

  1. 使用说明

    • 参数:目标数组,或者传递两个参数空数组和默认值;
    • 返回值:传目标数组则返回目标数组的第一项,传空数组和默认值则返回默认值。
  2. 使用代码示例
import { first } from 'radash'

const gods = ['lufee', 'loki', 'zeus']

first(gods) // => 'lufee'
first([], 'zuoluo') // => 'zuoluo'
  1. 源码解析
// 定义一个泛型函数 `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
}
  • 方法流程说明:

    1. 检查传入的数组 array 是否存在并且长度是否大于0。
    2. 如果数组存在且不为空(长度大于0),则返回数组的第一个元素 array[0]
    3. 如果数组不存在或为空,返回 defaultValue

    这个函数对于需要安全地访问数组第一个元素而不抛出错误的情况很有用,特别是在不确定数组是否为空的情况下。通过提供一个默认值,你可以避免在数组为空时访问未定义的索引。如果没有提供默认值,函数将默认返回 undefined

flat:数组扁平化 —— 把包含多个数组的数组转为一个数组(注意不会递归)

  1. 使用说明

    • 参数:包含多个数组的数组;
    • 返回值:降低一维后的数组;
    • 注意:不会递归降维,只能降一维
  2. 使用代码示例
import { flat } from 'radash'

const gods = [['shy', 'ning'], ['jkl']]

flat(gods) // => [shy, ning, jkl]
  1. 源码解析
// 定义一个泛型函数 `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` 为一个空数组。
}
  • 方法流程说明:

    1. 使用 reduce 方法遍历二维数组 listsreduce 方法的累加器 acc 是一个一维数组,用于收集所有子数组的元素。
    2. 对于 lists 中的每个子数组 list,使用展开语法 ... 将其元素添加到累加器数组 acc 中。
    3. 每次迭代结束后,返回更新的累加器 acc
    4. reduce 方法完成遍历后,返回最终的累加器 acc,这时它包含了 lists 中所有子数组的元素,形成了一个扁平化的一维数组。
    5. 提示:这个 flat 函数在功能上类似于 Array.prototype.flat 方法,但是它是手动实现的,适用于不支持内建 flat 方法的环境。

fork:按条件将数组拆分成两个数组,满足条件的一个,不满足条件的一个

  1. 使用说明

    • 参数:目标数组,条件函数;
    • 返回值:返回两个数组,一个保存满足条件的项,另一个保存不满足条件的项。
  2. 使用代码示例
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]]
  1. 源码解析
// 定义一个泛型函数 `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[]] // 初始化累加器为两个空数组。
)
}
  • 方法流程说明:

    1. 首先检查传入的数组 list 是否为空。如果为空,返回一对空数组。
    2. 使用 reduce 方法遍历 list 数组。reduce 方法的累加器 acc 是一个包含两个子数组的元组 [T[], T[]]
    3. 对于 list 中的每个元素 item,检查它是否满足条件函数 condition
    4. 如果条件函数返回 true,则将该元素添加到累加器的第一个子数组 a。如果条件函数返回 false,则将该元素添加到第二个子数组 b
    5. 在每次迭代结束后,返回更新后的累加器 [a, b]
    6. reduce 方法完成遍历后,返回最终的累加器 [a, b],它包含了根据条件函数分离的两个子数组。

group:根据条件函数指定的key构建一个统计对象,key 为指定的 key 有哪些 value ,value 为对应对象

  1. 使用说明

    • 参数:对象数组、条件函数;
    • 返回值:统计对象
  2. 使用代码示例
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] }
  1. 源码解析
// 定义一个泛型函数 `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[]>) // 初始化累加器为一个空对象。
}
  • 方法流程说明:

    1. 遍历传入的数组 array,对每个元素使用 getGroupId 函数来确定它应该属于哪个组。
    2. 对于每个元素,检查累加器 acc(一个对象)中是否已经有一个数组存在于以 groupId 为键的位置。如果没有,就在那个位置创建一个空数组。
    3. 将当前元素 item 添加到 acc[groupId] 数组中。
    4. 继续处理数组的下一个元素,直到所有元素都被处理完毕。
    5. 返回累加器 acc,它现在包含了按 groupId 分组的元素数组。
    6. tips:在TypeScript中,Partial<Record<Key, T[]>> 是一种类型,它表示一个对象,这个对象的键可以是 Key 类型,而每个键对应的值是 T[] 类型的数组。PartialRecord 都是TypeScript中的高级类型。

intersects:判断两个数组是否有公共项,返回一个布尔值

  1. 使用说明

    • 参数:数组1,数组2,可选条件函数(用于提取随机标识符,对对象数组进行操作时);
    • 返回值:有返回true,否则返回false。
  2. 使用代码示例
import { intersects } from 'radash'

const oceanFish = ['tuna', 'tarpon']
const lakeFish = ['bass', 'trout'] intersects(oceanFish, lakeFish) // => false const brackishFish = ['tarpon', 'snook'] intersects(oceanFish, brackishFish) // => true
  1. 源码解析
// 定义一个泛型函数 `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)])
}
  • 方法流程说明:

    1. 检查传入的数组 listAlistB 是否存在。如果任何一个不存在,返回 false
    2. 如果未提供 identity 函数,则使用一个默认函数,它将每个元素 x 强制转换为 K 类型,作为其唯一标识符。
    3. 遍历数组 listB,使用 reduce 方法和 ident 函数将其元素映射到一个记录对象 dictB 中,其中键是元素的唯一标识符,值为 true
    4. 使用 some 方法检查数组 listA 中是否有任何元素的唯一标识符存在于 dictB 中。如果存在,some 方法会返回 true,表示两个数组有交集。
    5. 如果 listA 中没有任何元素的唯一标识符在 dictB 中找到,some 方法返回 false,表示两个数组没有交集。
    6. 提示:??表示 TypeScript 中的空值合并运算符 。这个运算符用于提供一个默认值,当左侧的操作数 identitynullundefined 时,就会使用右侧的操作数作为默认值。x as unknown as K是 Typescript 的类型断言。

下期我们将介绍以下方法

  • iterate:把一个函数迭代执行指定次数;
  • last:输出数组的最后一项,如果数组为空则输出传入的默认值;
  • list:创建包含特定项的数组;
  • max:获取对象数组中指定标识符最大的项;
  • merge:合并数组,并且会覆盖第一个数组;
  • min:获取对象数组中指定标识符最小的项;
  • objectify:根据函数映射的键与值把数组转换为字典对象;
  • range:根据步长生成一个数值范围内的迭代值;
  • replaceOrAppend:替换对象数组中的项或是追加项(条件函数不满足时追加);
  • replace:替换数组中的第一个匹配项。

写在后面

  • 后续作者会整理一份方法目录上传,方便没法访问外网的朋友查看使用。
  • 该系列会在每周五更新,遇节假日提前。
  • 大家有任何问题或者见解,欢迎评论区留言交流!!!
  • 点击访问:radash 官网

lodash已死?radash最全使用介绍(附源码说明)—— Array方法篇(2)的更多相关文章

  1. php 品牌全车零件订购平台( 带采集数据 及 账号自动登陆【已绕过https证书加密】,php源码 ,QQ: 876635409 )

    php捷豹路虎 品牌全车零件订购平台  ( 带采集数据 及 账号自动登陆[已绕过https证书加密],php源码 ,QQ: 876635409 [由于咨询用户太多,请备注:汽车配件]) 一.php+m ...

  2. IPerf——网络测试工具介绍与源码解析(4)

    上篇随笔讲到了TCP模式下的客户端,接下来会讲一下TCP模式普通场景下的服务端,说普通场景则是暂时不考虑双向测试的可能,毕竟了解一项东西还是先从简单的情况下入手会快些. 对于服务端,并不是我们认为的直 ...

  3. 日志组件Log2Net的介绍和使用(附源码开源地址)

    Log2Net是一个用于收集日志到数据库或文件的组件,支持.NET和.NetCore平台. 此组件自动收集系统的运行日志(服务器运行情况.在线人数等).异常日志.程序员还可以添加自定义日志. 该组件支 ...

  4. 死磕 java同步系列之Phaser源码解析

    问题 (1)Phaser是什么? (2)Phaser具有哪些特性? (3)Phaser相对于CyclicBarrier和CountDownLatch的优势? 简介 Phaser,翻译为阶段,它适用于这 ...

  5. 死磕 java同步系列之StampedLock源码解析

    问题 (1)StampedLock是什么? (2)StampedLock具有什么特性? (3)StampedLock是否支持可重入? (4)StampedLock与ReentrantReadWrite ...

  6. 死磕 java同步系列之ReentrantLock源码解析(二)——条件锁

    问题 (1)条件锁是什么? (2)条件锁适用于什么场景? (3)条件锁的await()是在其它线程signal()的时候唤醒的吗? 简介 条件锁,是指在获取锁之后发现当前业务场景自己无法处理,而需要等 ...

  7. 死磕 java同步系列之ReentrantLock源码解析(一)——公平锁、非公平锁

    问题 (1)重入锁是什么? (2)ReentrantLock如何实现重入锁? (3)ReentrantLock为什么默认是非公平模式? (4)ReentrantLock除了可重入还有哪些特性? 简介 ...

  8. Android IntentService使用介绍以及源码解析

    版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.IntentService概述及使用举例 IntentService内部实现机制用到了HandlerThread,如果对HandlerThrea ...

  9. 死磕 java同步系列之CyclicBarrier源码解析——有图有真相

    问题 (1)CyclicBarrier是什么? (2)CyclicBarrier具有什么特性? (3)CyclicBarrier与CountDownLatch的对比? 简介 CyclicBarrier ...

  10. 死磕 java同步系列之Semaphore源码解析

    问题 (1)Semaphore是什么? (2)Semaphore具有哪些特性? (3)Semaphore通常使用在什么场景中? (4)Semaphore的许可次数是否可以动态增减? (5)Semaph ...

随机推荐

  1. QT - Day 5

    1    event事件 用途:用于事件的分发 也可以做拦截操作,不建议 bool event( QEvent * e); 返回值 如果是true 代表用户处理这个事件,不向下分发了 e->ty ...

  2. 【libGDX】使用Mesh绘制立方体

    1 前言 ​ 本文主要介绍使用 Mesh 绘制立方体,读者如果对 Mesh 不太熟悉,请回顾以下内容: 使用Mesh绘制三角形 使用Mesh绘制矩形 使用Mesh绘制圆形 ​ 在绘制立方体的过程中,主 ...

  3. http.Handler接口

    // 示例 // net/http package http type Handler interface{ ServeHTTP(w ResponseWriter, r *Request) } fun ...

  4. 矩池云 | GPU 分布式使用教程之 Pytorch

    GPU 分布式使用教程之 Pytorch Pytorch 官方推荐使用 DistributedDataParallel(DDP) 模块来实现单机多卡和多机多卡分布式计算.DDP 模块涉及了一些新概念, ...

  5. Html飞机大战(十四): 分数编辑和生命值设定

    好家伙,这章让我感受到了面向对象的优势了   1.分数设置 每个种类的敌机分数都设置好了, 那么当我们击毁不同的敌机后,加上不同的分数就行了 但是我们还是要想一下,   我要在哪里放这个分数增加的方法 ...

  6. Java 线程安全问题 使用同步机制讲单例模式中的懒汉式改写为线程安全的

    1 package bytezero.deadlock; 2 3 /** 4 * 使用同步机制讲单例模式中的懒汉式改写为线程安全的 5 * 6 * 7 * 8 * 9 * @author Byteze ...

  7. 如何查看apk安装包源代码??Android反编译apk,解包,打包,签名一体化实测 ,修改图片音频软件名称版本号等入门

    首先下载反编译工具包 下载地址 链接:  https://zly520.lanzoui.com/ibtuxhf7rab 一.反编译工具介绍 首先 如果你想改动图片音频之类的,见末尾! 1.apktoo ...

  8. npm包(npm install --legacy-bundling) 通过npm-pack-all 打包tgz,放到内网(不联网)nexus发布(npm publish)

    npm包(npm install --legacy-bundling) 通过npm-pack-all 打包tgz,放到内网(不联网)nexus发布(npm publish) 需求 内网不联网,安装指定 ...

  9. Set-Alias navi ./navi.bat - 设置别名 - powershell入门 (后期改方案了,换npm script)

    需求 开机要启动好几个服务,原先都用vscode启动,觉得可能比较占内存,所以改成命令行 发现直接运行bat,需要输入./batName.bat 一次还行,天天输入就麻烦了 命令 Set-Alias ...

  10. 五大基础dp

    动规条件 • 最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构, 即满足最优化原理. • 无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响.也就是说,某状 ...