前言
自己做了几年后端开发,在项目中使用链表去重的机会并不多,笔试的时候也经常被问到。 就我个人而言,我理解这个问题确实测试了 JavaScript 的基础知识。 因为有很多方法可以做到这一点。 这次根据这道题,把相关的知识都搞明白了。
1.ES6中的NewSet形式
首先看MDN上Set的描述:
设置对象允许您存储任何类型的唯一值,无论是原始值还是对象引用。
Set 对象是值的集合javascript 数组 重复,您可以按照插入顺序对其元素进行迭代。 Set中的元素只会出现一次javascript 数组 重复,即Set中的元素是唯一的。
关键字:可以存储任何类型,并且存储的值是唯一的,这样可以先去除链表中的重复数据。
const list1 = [1, 2, 3, 7, 11, 56, 3, 2, 4, 5] const list2 = new Set(list1) console.log(list2)
看一下返回的结果:
从结果可以看出,返回的是一个可迭代的Set对象,此时需要将Set对象转换为链表。此时可用
大批。 从()。
**Array.from()** 方法从类似链表或可迭代的对象创建一个新的浅复制链表实例。
碰巧 newSet() 返回一个可迭代对象。
const list3 = Array.from(new Set([null, null, undefined, 12, undefined, 7, 2, 1, 22, 2, function a(){}, function a(){}, {}, {}]))
结果是返回一个链表:
这些方法不考虑兼容性,无法去除重复的函数和{}
Array.from() 的扩展
Array.from(arrayLike[,mapFn[,thisArg]])
arrayLike:伪链表和可迭代对象
mapFn:每个元素都会执行这个bounce方法
thisArg:执行bounce函数时的this点。
const list4 = Array.from("name", arg => arg + 12) console.log(list4) // [ "n12", "a12", "m12", "e12" ]
伪链表对象(任何具有长度属性和多个索引属性的对象,例如字符串)
可迭代对象(可以获取对象中的元素,如Map和Set等)
2.集合的另一种写法
const list20 = [5, 3, 5, 5, 6, 37, 22, 22] console.log([...new Set(list20)])
虽然和第一部类似
3. 嵌套for循环
const list5 = [null, null, undefined, undefined, {}, {}, function q() {}, function q() {}, 34, 2, 1, 2] for(let i = 0; i < list3.length; i++) { for (let j = i + 1; j < list3.length; j++) { if (list3[i] === list3[j]) { list3.splice(j, 1) // 将重复的数据删掉一个 j-- // 因为删除掉了一个元素,就从这个元素的索引重新开始 } } }
这些方法使用了 splice(index, num) 的方法,返回的结果并没有移除函数和对象。 我们能想到的最简单的方法就是这些形式的重复数据删除。
四、indexOf形式
const list6 = [null, null, undefined, undefined, NaN, NaN, false, "false", function a(){}, function a() {}, {}, {}] const list7 = [] for(let k = 0; k<list6.length; k++) { if (list7.indexOf(list6[k]) === -1) { list7.push(list6[k]) } } console.log(list7, "list7") // [null, undefined,NaN, NaN,false,"false",[Function: a], [Function: a],{},{}] list7
关于indexOf
这个技巧在数组构造函数和字符串构造函数的原型上都可用
MDN 上对它们的解释是:
**indexOf()** 方法返回在链表中可以找到给定元素的第一个索引,如果不存在则返回 -1。
arr.indexOf(searchElement[, fromIndex])
**indexOf()** 方法返回调用它的 String 对象中指定值第一次出现的索引,并从 fromIndex 开始搜索。 如果未找到该值,则返回 -1。
str.indexOf(searchValue [, fromIndex])
从这一点就可以看出两者的用法是一样的。
五、排序
我们看一下关于sort的解释:
**sort()** 方法使用就地算法对链表的元素进行排序并返回字段。默认排序顺序是在将元素转换为字符串然后比较它们的 UTF-16 代码单元序列时建立的价值观
因为要看具体的实现,所以很难保证排序的时间复杂度和空间复杂度。
因此,当链表很长时,这些方法可能无法保证性能。 用它来减肥有哪些想法? 首先使用sort进行排序,然后比较前一个和后一个,这样相同的值始终是相邻关系。
const list8 = [null, null, undefined, undefined, NaN, NaN, false, "false", function a(){}, function a() {}, {}, {}] const list9 = list8.sort() const list10 = [list9[0]] for(let i = 1; i<list9.length; i++) { if (list9[i] !== list9[i-1]) { list10.push(list9[i]) } }
这很容易理解。
六、包括
const list11 = [null, null, undefined, undefined, NaN, NaN, false, "false", function a(){}, function a() {}, {}, {}] const list12 = [] for (let i = 0; i<list11.length ; i++) { if (!list12.includes(list11[i])) { list12.push(list11[i]) } }
在此结果中,函数和 {} 未进行重复数据删除,其他所有内容均已进行重复数据删除。
include 也是 Array 构造函数和 String 构造函数上的方法。
七、filter和indexOf
// 数组去重方式6-filter和indexOf const list13 = [1, 2, 3, 3, 5] const list14 = list13.filter((item, index, arr) => { // 也就是在遍历这个数组list13的时候,每次拿当前的元素跟此数组中这个元素第一次出现的位置相比,如果位置是一致的,就返回当前元素 return list13.indexOf(item, 0) === index })
8. 递归
const list15 = [1, 2, 3, 4, 5, 7, 6, 4, 3] const list16 = list15 const len = list16.length list16.sort(function(a, b) { return a - b }) // 先排序 function loop(index) { if (index >= 1) { if (list16[index] === list16[index - 1]) { list16.splice(index, 1) } loop(index - 1) } } loop(len - 1)
关于排序
我们在排序的时候可能会忽略一个问题,可能得不到我们想要的结果,比如下面的例子:
const list17 = [22, 1, 2, 15, 3, 4, 3, 1, 11] console.log(list17.sort()) // [1, 1, 11, 15, 2, 22, 3, 3, 4]
看看得到的结果,根本就不是按照从小到大的排名。 这是因为默认排序顺序是在将元素转换为字符串然后比较它们的 UTF-16 代码单元值序列时建立的。
所以要找到另一种排序方式就是传递一个函数来排序。
编曲排序([比较函数])
范围:
返回值:
返回的是一个已经排序好的链表。
9.利用Map数据结构排序
const list 18 = [2, 3, 33, 2, 5, 1, 3] const map1 = new Map() for(let i = 0; i<list18.length; i++) { if (map1.get(list18[i])) { map1.set(list18[i], true) } else { map1.set(list18[i], false) list19.push(list18[i]) } }
这个比较容易理解,就不多说了。
总结
关于JavaScript链表去重的一些理解这篇文章就到此结束了。 更多相关JavaScript链表去重内容,请搜索云海天教程往期文章或继续浏览下方相关文章。 希望大家以后多多支持云海。 日教程!
原文链接:
发表评论