在实际工作中推荐直接使用这种方法去重,方便实惠。Set
对象是值的集合,你可以按照插入的顺序迭代它的元素。Set中的元素只会出现一次,即 Set 中的元素是唯一的。
function removeDuplicate_1(arr) {
return [... new Set(arr)]
}
上面其实相当于 let set = new Set(arr);
return [... set];
这里set
是一个集合对象,通过...结构的方式,将每一项解构到数组中。
下面的if条件可以这样写,if(prev.indexOf(cur) === -1)
,是indexOf()方法,prev里还没有,就push 近result.push, 有就不入result数组,
function removeDuplicate_2(arr) {
arr.sort((a, b) => a - b) // 数组升序排序
return arr.reduce((prev, cur) => { // 这里return最后结果就是prev 的最后结果
// 第一次数组为空时|| prev 数组的最后一项不等于arr 的下一项的话 ,把当前项cur push到prev数组中,
if (prev.length === 0 || (prev[prev.length - 1] !== cur)) {
prev.push(cur)
}
return prev; // 这里返回的prev 会成为 reduce(prev,cur)这里prev 的新值
}, [])
}
一般写arr.reduce((p,c)=>{ fn content;return p },init)
,将下面的具体参数介绍对号入座。
概括:reduce参数包括一个函数和一个初始值,初始值可选,函数有四个参数可选,有初始值 时previousValue = 初始值(initialValue), currentValue = 数组第一项arr[0],无初始值时, p = arr [0], c = arr[1]。return的结果作为下一次迭代的 p的初始值。
一个 “reducer” 函数,包含四个参数:
previousValue
:上一次调用 callbackFn
时的返回值。在第一次调用时,若指定了初始值 initialValue
,其值则为 initialValue
,否则为数组索引为 0 的元素 array[0]
。
currentValue
:数组中正在处理的元素。在第一次调用时,若指定了初始值 initialValue
,其值则为数组索引为 0 的元素 array[0]
,否则为 array[1]
。
currentIndex
:数组中正在处理的元素的索引。若指定了初始值 initialValue
,则起始索引号为 0,否则从索引 1 起始。
array
:用于遍历的数组。
initialValue
可选
作为第一次调用 callback
函数时参数 previousValue 的值。若指定了初始值 initialValue
,则 currentValue
则将使用数组第一个元素;否则 previousValue
将使用数组第一个元素,而 currentValue
将使用数组第二个元素。
用途
(1)、求数组所有值的和
let sum = [0, 1, 2, 3].reduce(function (previousValue, currentValue) {
return previousValue + currentValue
}, 0)
// sum is 6
(2)、累加对象数组里的值
let initialValue = 0
let sum = [{x: 1}, {x: 2}, {x: 3}].reduce(
(previousValue, currentValue) => previousValue + currentValue.x
, initialValue
)
console.log(sum) // logs 6
更多实例参考官方文档
看看有无初始值的情况
无初始值时 reduce() 如何运行
假如运行以下无初始值的 reduce()
代码:
const array = [15, 16, 17, 18, 19];
function reducer(previous, current, index, array) {
const returns = previous + current;
console.log(`previous: ${previous}, current: ${current}, index: ${index}, returns: ${returns}`);
return returns;
}
array.reduce(reducer);
callback 被调用四次,每次调用的参数和返回值如下表:
callback iteration |
previousValue |
currentValue |
currentIndex |
array |
return value |
---|---|---|---|---|---|
first call | 15 |
16 |
1 |
[15, 16, 17, 18, 19] |
31 |
second call | 31 |
17 |
2 |
[15, 16, 17, 18, 19] |
48 |
third call | 48 |
18 |
3 |
[15, 16, 17, 18, 19] |
66 |
fourth call | 66 |
19 |
4 |
[15, 16, 17, 18, 19] |
85 |
由 reduce()
返回的值将是最后一次回调返回值(85
)。
有初始值时 reduce() 如何运行
在这里,我们以相同的算法 reduce 同一个数组,但提供 10
作为初始值:
[15, 16, 17, 18, 19].reduce( (previousValue, currentValue, currentIndex, array) => previousValue + currentValue, 10 )
Copy to Clipboard
callback iteration |
previousValue |
currentValue |
currentIndex |
array |
return value |
---|---|---|---|---|---|
first call | 10 |
15 |
0 |
[15, 16, 17, 18, 19] |
25 |
second call | 25 |
16 |
1 |
[15, 16, 17, 18, 19] |
41 |
third call | 41 |
17 |
2 |
[15, 16, 17, 18, 19] |
58 |
fourth call | 58 |
18 |
3 |
[15, 16, 17, 18, 19] |
76 |
fifth call | 76 |
19 |
4 |
[15, 16, 17, 18, 19] |
95 |
这种情况下 reduce()
返回的值是 95
。
(1)、声明一个新数组result
来存放,去重后的数组 。
(2)、给数组排序。
(3)、循环排序后的数组, 若第i项
不等于第i-1项
,则把此项内容push到result数组,注意这里和常规的,用当前项于下一项对比的方式不同, arr[i- 1]
这里是arr[-1],结果是undefined的,js 语言的特性,所以可以这样操作吧
思考一下(1)
用if(arr[i] !== arr[i + 1])
可以吗,评论区说出你的答案,为什么?
(4)、 返回结果result
function removeDuplicate_3(arr) {
let result = []
arr.sort((a, b) => a - b)
for (let i = 0; i < arr.length; i++) {
if (arr[i] !== arr[i - 1]) {
result.push(arr[i])
}
}
return result
}
sort 方法介绍
arr.sort((a, b) => a - b) // 升序
arr.sort((a, b) => b - a) // 降序
function removeDuplicate_4(arr) {
let result = [];
for (let i = 0; i < arr.length; i++) {
if (result.indexOf(arr[i]) == -1) {
result.push(arr[i])
}
}
return result;
}
indexOf() 方法介绍
indexOf()
方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。
概括:接收两个参数,返回下标值。arr.indexOf(要查找的元素,从那个位置开始查找)
示例
var array = [2, 5, 9];
array.indexOf(2); // 0
array.indexOf(7); // -1
array.indexOf(9, 2); // 2
array.indexOf(2, -1); // -1
array.indexOf(2, -3); // 0
indexOf()方法详细介绍
function removeDuplicate_5(arr) {
return Array.from(new Set(arr))
}
Array.from()
方法对一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。
概括:接收三个参数,返回数组。Array.from(要处理的类数组对象,fn【回调函数可选】, this【执行回调函数时的this指向,可选】)
注意:使用的时Array.from ,而不是数组实例arr.from,类似于Java的静态方法用类名调用。
Array.From() 详细介绍
function removeDuplicate_6(arr) {
let result = [], obj = {};
for (let item of arr) {
if (!obj[item]) {
result.push(item);
obj[item] = 1
} else {
obj[item]++
}
}
return result;
}
function removeDuplicate_7(arr) {
return Array.prototype.filter.call(arr, (item, index) => {
return arr.indexOf(item) === index
})
}
function removeDuplicate_8(arr) {
let fast = 0, low = -1, result = [];
arr.sort((a,b) => a - b)
while (fast < arr.length) {
if (arr[fast] !== arr[low]) {
result.push(arr[fast])
}
fast++
low++
}
return result;
}
Map
对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者原始值) 都可以作为一个键或一个值。Map 对象filter()
方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。
let arr_obj = [
{
id: 1,
name: '张三',
age: 18,
sex: 1
},
{
id: 2,
name: '李四',
age: 20,
sex: 2
},
{
id: 1,
name: '张三',
age: 18,
sex: 1
},
{
id: 3,
name: '王老五',
age: 18,
sex: 2
},
{
id: 4,
name: '王老五',
age: 18,
sex: 2
}
]
function removeDuplicate_10(arr, attr) {
const result = new Map();
return arr.filter((item) => !result.has(item[attr]) && result.set(item[attr], 1))
}
console.log(arr_obj);
console.log(removeDuplicate_10(arr_obj, 'name')); // 以对象姓名去重
上面filter()里面的内容会不好理解吗
它相当于
function removeDuplicate_11(arr, attr) {
const result = new Map();
let fn = (item) => {
if(!result.has(item[attr])) {
return result.set(item[attr], 1)
}
}
return arr.filter(fn)
}
!result.has(item[attr]) && result.set(item[attr], 1)) 相当于
if(!result.has(item[attr])) {
result.set(item[attr], 1)
}
//由于箭头函数没有带{}花括号,所以是有return的, 所以会相当于这样
if(!result.has(item[attr])) {
return result.set(item[attr], 1)
}
去重前
[
{ id: 1, name: '张三', age: 18, sex: 1 },
{ id: 2, name: '李四', age: 20, sex: 2 },
{ id: 1, name: '张三', age: 18, sex: 1 },
{ id: 3, name: '王老五', age: 18, sex: 2 },
{ id: 4, name: '王老五', age: 18, sex: 2 }
]
去重后
[
{ id: 1, name: '张三', age: 18, sex: 1 },
{ id: 2, name: '李四', age: 20, sex: 2 },
{ id: 3, name: '王老五', age: 18, sex: 2 }
]
以id 去重
console.log(removeDuplicate_8(arr_obj, 'id'));
[
{ id: 1, name: '张三', age: 18, sex: 1 },
{ id: 2, name: '李四', age: 20, sex: 2 },
{ id: 3, name: '王老五', age: 18, sex: 2 },
{ id: 4, name: '王老五', age: 18, sex: 2 }
]
思路是创建一个空对象,判断对象里有没有该属性的值,没有就吧该项push 到数组存储
function removeDuplicate_12(arr, attr) {
let obj = {}
return arr.reduce((prev,curr) =>{
// 这种三元运算符的方式是不是不好理解,看看下面10的做法,转化为if判断就好理解了。
obj[curr[attr]] ? '' : obj[curr[attr]] = true && prev.push(curr) // ''为空的意思
// 写法上也可以 为undefined
// obj[curr[attr]] ? undefined : obj[curr[attr]] = true && prev.push(curr)
return prev
},[])
}
console.log(removeDuplicate_12(arr_obj, 'name'));
思路和9的类似,知识迭代方式不同。
function removeDuplicate_13(arr, attr) {
let obj = {}, result = [];
for(let item of arr){
if(!obj[item[attr]]) {
result.push(item)
obj[item[attr]] = true
}
}
return result;
}
console.log(removeDuplicate_13(arr_obj, 'id'));
作者:怕浪小乌龟
https://juejin.cn/post/7081572865220280333
欢迎关注前端之阶公众号,获取更多前端知识,加入前端大群,与知名互联网大佬做朋友,开启共同学习新篇章!