lodash已死?radash最全使用介绍(附源码说明)—— Array方法篇(2)
前言
- 前篇我们已经介绍了 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 官网
lodash已死?radash最全使用介绍(附源码说明)—— Array方法篇(2)的更多相关文章
- php 品牌全车零件订购平台( 带采集数据 及 账号自动登陆【已绕过https证书加密】,php源码 ,QQ: 876635409 )
php捷豹路虎 品牌全车零件订购平台 ( 带采集数据 及 账号自动登陆[已绕过https证书加密],php源码 ,QQ: 876635409 [由于咨询用户太多,请备注:汽车配件]) 一.php+m ...
- IPerf——网络测试工具介绍与源码解析(4)
上篇随笔讲到了TCP模式下的客户端,接下来会讲一下TCP模式普通场景下的服务端,说普通场景则是暂时不考虑双向测试的可能,毕竟了解一项东西还是先从简单的情况下入手会快些. 对于服务端,并不是我们认为的直 ...
- 日志组件Log2Net的介绍和使用(附源码开源地址)
Log2Net是一个用于收集日志到数据库或文件的组件,支持.NET和.NetCore平台. 此组件自动收集系统的运行日志(服务器运行情况.在线人数等).异常日志.程序员还可以添加自定义日志. 该组件支 ...
- 死磕 java同步系列之Phaser源码解析
问题 (1)Phaser是什么? (2)Phaser具有哪些特性? (3)Phaser相对于CyclicBarrier和CountDownLatch的优势? 简介 Phaser,翻译为阶段,它适用于这 ...
- 死磕 java同步系列之StampedLock源码解析
问题 (1)StampedLock是什么? (2)StampedLock具有什么特性? (3)StampedLock是否支持可重入? (4)StampedLock与ReentrantReadWrite ...
- 死磕 java同步系列之ReentrantLock源码解析(二)——条件锁
问题 (1)条件锁是什么? (2)条件锁适用于什么场景? (3)条件锁的await()是在其它线程signal()的时候唤醒的吗? 简介 条件锁,是指在获取锁之后发现当前业务场景自己无法处理,而需要等 ...
- 死磕 java同步系列之ReentrantLock源码解析(一)——公平锁、非公平锁
问题 (1)重入锁是什么? (2)ReentrantLock如何实现重入锁? (3)ReentrantLock为什么默认是非公平模式? (4)ReentrantLock除了可重入还有哪些特性? 简介 ...
- Android IntentService使用介绍以及源码解析
版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.IntentService概述及使用举例 IntentService内部实现机制用到了HandlerThread,如果对HandlerThrea ...
- 死磕 java同步系列之CyclicBarrier源码解析——有图有真相
问题 (1)CyclicBarrier是什么? (2)CyclicBarrier具有什么特性? (3)CyclicBarrier与CountDownLatch的对比? 简介 CyclicBarrier ...
- 死磕 java同步系列之Semaphore源码解析
问题 (1)Semaphore是什么? (2)Semaphore具有哪些特性? (3)Semaphore通常使用在什么场景中? (4)Semaphore的许可次数是否可以动态增减? (5)Semaph ...
随机推荐
- Conda简单教程
目录 什么是Conda 安装Conda 虚拟环境管理 模块管理 何时使用Conda 什么是Conda Conda是Python中用于管理包和虚拟环境的一大利器. 使用Conda可以非常便利的使用数据科 ...
- flutter打包android的一些配置修改(解决白屏,视频闪退)
1.打包后视频播放闪退 视频播放器选择了flutter_tencentplayer(https://github.com/qq326646683/flutter_tencentplayer) 解决:不 ...
- Qt+QtWebApp开发笔记(六):http服务器html实现静态相对路径调用第三方js文件
前言 前面做了一些交互,网页是直接通过html对response进行返回的,这里QtWebApp与传统的web服务器不同,传统的web服务器可以调用同级目录相对路径或者绝对路径下的js,而QtWe ...
- python文件加锁模块之fcntl
# 示例 import fcntl with open('./test.txt', 'w') as f: fcntl.flock(f, fcntl.LOCK_EX) # 对文件加锁,除加锁进程外其它进 ...
- 【Azure 应用服务】遇见“无法创建hybrid connection for App Service”的解决办法
Hybrid Connection (混合连接) 在两个联网应用程序之间启用了双向.请求-响应和二进制流通信以及简单的数据报流.通过混合连接,可以实现应用部署在公网环境中,而数据库保存在本地私网环境中 ...
- Android\C++\C#\Java
关于:(38条消息) 千万不能错过的Android NDK下载安装及配置_石子君的博客-CSDN博客_android ndk下载 (38条消息) Android扩展知识 - so文件生成及其使用_L- ...
- Codeforces(1500板刷)
目录 写在前面 1. A. Did We Get Everything Covered?(构造.思维) 题目链接 题意 题解 代码 总结 2 F. Greetings(离散化+树状数组) 题目链接 题 ...
- TLS原理与实践(二)
主页 个人微信公众号:密码应用技术实战 个人博客园首页:https://www.cnblogs.com/informatics/ 引言 在上一篇博客中,我们通过<一文读懂TLS1.2协议](ht ...
- Asp .Net Core 系列:Asp .Net Core 集成 Hangfire+MySQL
简介 https://www.hangfire.io/ 在 .NET 和 .NET Core 应用程序中执行后台处理的简单方法,无需 Windows 服务或单独的进程. Hangfire 是一个开源的 ...
- 一张图搞清楚wait、sleep、join、yield四者区别,面试官直接被征服!
写在开头 在线程的生命周期中,不同状态之间切换时,可以通过调用sleep().wait().join().yield()等方法进行线程状态控制,针对这一部分知识点,面试官们也会做做文章,比如问你这些方 ...