Appearance
uniqueBy
uniqueBy 对象去重
用于对“对象数组”进行去重,支持按指定键(点路径)或选择器函数生成唯一键进行去重;可选择保留第一次或最后一次出现的元素。
一、引入与使用
支持两种方式引入:
ts
// 方式一:按需子路径引入(推荐)
import { uniqueBy } from '@cuixingjian/cui-utils/uniqueBy'
// 方式二:从包入口命名导出引入
import { uniqueBy } from '@cuixingjian/cui-utils'二、使用示例
ts
import { uniqueBy } from '@cuixingjian/cui-utils/uniqueBy'
const list = [
{ id: 1, name: 'cui', info: { tag: 'ui' } },
{ id: 2, name: 'cui' },
{ id: 1, name: 'cui', info: { tag: 'framework' } },
]
// 1) 按单键去重(保留首次出现)
const byId = uniqueBy(list, 'id')
// 结果: [{ id:1, name:'cui', info:{tag:'ui'} }, { id:2, name:'cui' }]
// 2) 按多键组合去重(id + name)
const byIdName = uniqueBy(list, ['id', 'name'])
// 结果: 与 byId 相同,因为 name 相同
// 3) 选择器函数生成唯一键(自定义逻辑)
const bySelector = uniqueBy(list, (item) => `${item.id}-${item.name}`)
// 4) 保留最后一次出现(覆盖先前元素)
const keepLast = uniqueBy(list, 'id', { keep: 'last' })
// 结果: id=1 的元素取最后一个,即 info.tag 为 'framework'
// 5) 无选择器/键时:原始值按值去重,对象按 JSON 字符串去重
const nums = uniqueBy([1, 1, 2, 2, 3]) // [1,2,3]
const objs = uniqueBy([{ a: 1 }, { a: 1 }]) // [{ a:1 }]三、API
| 方法 | 说明 | 类型 |
|---|---|---|
| uniqueBy | 对对象数组进行去重并返回新数组 | <T>(list: T[], selector?: ((item: T) => unknown) | string | string[], options?: UniqueByOptions) => T[] |
参数
| 参数名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| list | 需要去重的数组 | T[] | — |
| selector | 唯一键生成方式:函数、单键(点路径)或多键数组 | ((item: T) => unknown) | string | string[] | — |
| options | 去重选项 | UniqueByOptions | { keep: 'first' } |
UniqueByOptions
| 字段 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| keep | 重复项保留策略:first 保留首次;last 保留最后一次 | 'first' | 'last' | 'first' |
返回值
| 名称 | 说明 | 类型 |
|---|---|---|
| result | 去重后的新数组 | T[] |
四、注意事项
selector为字符串时支持点路径(如"info.tag")。为多键数组时会按顺序拼接值生成唯一键。- 未指定
selector时,对象通过JSON.stringify的结果去重,属性顺序会影响结果;如需稳健的深度比较,请使用选择器函数明确生成唯一键。 - 该函数不修改原数组,返回新数组。
五、源码
展开查看
ts
// 源码来自 @cuixingjian/cui-utils/uniqueBy
export type KeySelector<T> = (item: T) => unknown
export interface UniqueByOptions {
keep?: 'first' | 'last'
}
function getByPath(obj: any, path: string): unknown {
const parts = path.split('.')
let cur = obj
for (const p of parts) {
if (cur == null) return undefined
cur = cur[p]
}
return cur
}
export function uniqueBy<T>(
list: T[],
selector?: KeySelector<T> | string | string[],
options: UniqueByOptions = {}
): T[] {
const { keep = 'first' } = options
if (!Array.isArray(list) || list.length === 0) return []
const map = new Map<unknown, T>()
const makeKey = (item: T): unknown => {
if (typeof selector === 'function') {
return selector(item)
}
if (typeof selector === 'string') {
return getByPath(item as any, selector)
}
if (Array.isArray(selector)) {
return selector.map((k) => getByPath(item as any, k)).join('|')
}
if (item === null) return item
const t = typeof item
if (t === 'object') return JSON.stringify(item)
return item as unknown
}
for (const it of list) {
const key = makeKey(it)
if (!map.has(key)) {
map.set(key, it)
} else if (keep === 'last') {
map.set(key, it)
}
}
return Array.from(map.values())
}