前言

  • 前篇我们已经介绍了 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. 【Android 逆向】r0zapataNative.apk 破解

    1. apk 安装到手机,需要输入内容,随便输入,提示fail... 2. apk 导入到jadx中查看一下 MainActivity.java String textData = "b2F ...

  2. linux下virtualenvwrapper安装

    安装 pip3 install virtualenvwrapper -i https://pypi.douban.com/simple 设置linux的用户配置文件配置virtualenvwrappe ...

  3. Elasticsearch系列之-linux.docker安装和基础操作及在Django中集成

    elasticsearch Elasticsearch是一个基于Lucene的搜索服务器,也是属于NoSQL阵营的数据库.它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口提供 ...

  4. DataGear数据可视化分析平台介绍

    DataGear 是一款开源免费的数据可视化分析平台,自由制作任何您想要的数据看板,支持接入SQL.CSV.Excel.HTTP接口.JSON等多种数据源. 系统特点: 友好的数据源接入 支持运行时接 ...

  5. 八: Mysql配置文件的使用

    # Mysql配置文件的使用 1. 配置文件格式 与在命令行中指定启动选项不同的是,配置文件中的启动选项被划分为若干个组,丽个组有一个组名, 用中括号 [ ]扩起来,像这样: 像这个配置文件里就定义了 ...

  6. spring MVC常用配置模板

    第一个  log4j 最简化配置,复制可以,新建一个 log4j.xml <?xml version="1.0" encoding="UTF-8" ?&g ...

  7. XAF Blazor 中使用 Blazor 组件

    前言 文章的标题是不是感觉有点奇怪,但实际我们在XAFBlazor中使用Blazor组件是很繁琐的,我们需要将Blazor组件封装成属性编辑器(PropertyEditor),再用非持久化对象(Non ...

  8. 删除文件或目录 被进程占用或锁定locked 查询进程 资源监视器-cpu-关联句柄-输入文件全路径

    删除文件或目录 被进程占用或锁定 查询进程 资源监视器-cpu-关联句柄-输入文件全路径 右键点击桌面的Win图标,点击"任务管理器">>点击左上角"性能&q ...

  9. 用python进行二进制bin文件合并

    一 基本概念 bin文件合并是嵌入式中常用的,这里给一个实例. 二  实例分析 import os import argparse import hashlib offset1 = 0x0010000 ...

  10. In-batch negatives Embedding模型介绍与实践

    语义索引(可通俗理解为向量索引)技术是搜索引擎.推荐系统.广告系统在召回阶段的核心技术之一.语义索引模型的目标是:给定输入文本,模型可以从海量候选召回库中快速.准确地召回一批语义相关文本.语义索引模型 ...