01.遍历操作
01.forEach方法
01.使用讲解
forEach方法中的function回调有三个参数:
- 第一个参数是遍历的数组内容,
- 第二个参数是对应的数组索引,
- 第三个参数是数组本身
foreach 语法:
/*
* JS中还为我们提供了—个方法,用来遍历数组
* forEach()
* -这个方法只支持IE8以上的浏览器
* forEach()方法需要一个函数作为参数
-像这种函数,由我们创建但是不由我们调用的,我们称为回调函数(由浏览器调用)
-数组中有几个元素函数就会执行几次
-每次执行时,浏览器会将遍历到的元素以实参的形式传递进来 我们可以来定义形参,来读取这些内容
-浏览器会在回调函数中传递三个参数;
第一个参数,就是当前正在遍历的元素
第二个参数,就是当前正在遍历的元素的索引
第三个参数,就是正在遍历的数组
*/
数组.forEach(function(value , index , obj){
});
示例 常规用法
var array = ['a', 'b', 'c'];
array.forEach(function(element) {
console.log(element);
});
//a b c
全面示例
var arr = [1,2,3,4];
var sum =0;
arr.forEach(function(value,index,array){
array[index] == value; //结果为true
sum+=value;
});
console.log(sum); //结果为 10
02.leetcode典型例题 最小操作次数使数组元素相等
题目
给定一个长度为 n 的 非空 整数数组,每次操作将会使 n - 1 个元素增加 1。找出让数组所有元素相等的最小操作次数。
示例:
输入:
[1,2,3]
输出:
3
解释:
只需要3次操作(注意每次操作会增加两个元素的值):
[1,2,3] => [2,3,3] => [3,4,3] => [4,4,4]
题解
/**
* @param {number[]} nums
* @return {number}
*/
var minMoves = function(nums) {
let min = nums[0];
let res = 0;
for(let i =0;i<nums.length;i++) {
min = Math.min(min,nums[i])
}
// for(let j=0;j<nums.length;j++) {
// res+=nums[j]-min
// }
nums.forEach(values=>{
res+=values-min
})
return res
};
03.打断forEach
https://blog.csdn.net/handy_csdn/article/details/105170806
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uEKb7gnm-1629886228971)(20200328215017563.png)]
给你一个排序后的字符列表 letters ,列表中只包含小写英文字母。另给出一个目标字母 target,请你寻找在这一有序列表里比目标字母大的最小字母。
在比较时,字母是依序循环出现的。举个例子:
如果目标字母 target = 'z' 并且字符列表为 letters = ['a', 'b'],则答案返回 'a'
示例:
输入:
letters = ["c", "f", "j"]
target = "a"
输出: "c"
输入:
letters = ["c", "f", "j"]
target = "c"
输出: "f"
输入:
letters = ["c", "f", "j"]
target = "d"
输出: "f"
输入:
letters = ["c", "f", "j"]
target = "g"
输出: "j"
输入:
letters = ["c", "f", "j"]
target = "j"
输出: "c"
输入:
letters = ["c", "f", "j"]
target = "k"
输出: "c"
/**
* @param {character[]} letters
* @param {character} target
* @return {character}
*/
var nextGreatestLetter = function(letters, target) {
var res ='';
try{
letters.forEach(item=>{
if(item>target){
res = item
throw new Error('找到数据')
}
})
}catch{
return res
}
res=letters[0]
return res
};
02.filter方法
01.使用详解
定义和用法
- filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
- 注意:** filter() 不会对空数组进行检测。
- 注意: filter() 不会改变原始数组。
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J8W2Zg2F-1629886228974)(https://raw.githubusercontent.com/17713679014/my_picgo/main/img/image-20210722212055598.png)]
利用 filter 遍历出所有偶数:
let arr = [56, 15, 48, 3, 7];
let newArr = arr.filter(function (value, index, array) {
return value % 2 === 0;
});
console.log(newArr)
// [56, 48]
利用 filter 进行数组去重:
function unique(arr) {
return arr.filter(function(item, index, arr) {
//当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
return arr.indexOf(item, 0) === index;
});
}
var arr = [1,1,'RUNOOB','RUNOOB',true,true,15];
console.log(unique(arr))
// [1, "RUNOOB", true, 15]
取数组交集
// 02.交集
let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
let arr2 = [3, 4, 5, 6, 5, 4, 3];
// 看来我需要学学数组的一些方法
let result = [...new Set(arr)].filter(item => new Set(arr2).has(item));
console.log(result);
02.典型例题
01.500. 键盘行
给你一个字符串数组 words ,只返回可以使用在 美式键盘 同一行的字母打印出来的单词。键盘如下图所示。
美式键盘 中:
第一行由字符 "qwertyuiop" 组成。
第二行由字符 "asdfghjkl" 组成。
第三行由字符 "zxcvbnm" 组成。
示例 1:
输入:words = ["Hello","Alaska","Dad","Peace"]
输出:["Alaska","Dad"]
示例 2:
输入:words = ["omk"]
输出:[]
示例 3:
输入:words = ["adsdf","sfd"]
输出:["adsdf","sfd"]
02.题解
https://leetcode-cn.com/problems/keyboard-row/solution/jian-pan-xing-by-ouuz-2/
解题思路
直接利用正则求解就可以了
可以直接利用库函数不用每次都写循环
修饰符用i,不用gi,gi会全局匹配,导致结果会漏掉
基础知识:
g: 全局匹配
i: 忽略大小写
gi: 以上组合
^ 匹配一个输入或一行的开头,/^a/匹配"an A",而不匹配"An a"
$ 匹配一个输入或一行的结尾,/a$/匹配"An a",而不匹配"an A"
* 匹配前面元字符0次或多次,/ba*/将匹配b,ba,baa,baaa
+ 匹配前面元字符1次或多次,/ba+/将匹配ba,baa,baaa
? 匹配前面元字符0次或1次,/ba?/将匹配b,ba
(x) 匹配x保存x在名为$1...$9的变量中
x|y 匹配x或y
{n} 精确匹配n次
{n,} 匹配n次以上
{n,m} 匹配n-m次
[xyz] 字符集(character set),匹配这个集合中的任一一个字符(或元字符)
[^xyz] 不匹配这个集合中的任何一个字符
[\b] 匹配一个退格符
\b 匹配一个单词的边界
\B 匹配一个单词的非边界
\cX 这儿,X是一个控制符,/\cM/匹配Ctrl-M
\d 匹配一个字数字符,/\d/ = /[0-9]/
\D 匹配一个非字数字符,/\D/ = /[^0-9]/
\n 匹配一个换行符
\r 匹配一个回车符
\s 匹配一个空白字符,包括\n,\r,\f,\t,\v等
\S 匹配一个非空白字符,等于/[^\n\f\r\t\v]/
\t 匹配一个制表符
\v 匹配一个重直制表符
\w 匹配一个可以组成单词的字符(alphanumeric,这是我的意译,含数字),包括下划线,如[\w]匹配"$5.98"中的5,等于[a-zA-Z0-9]
\W 匹配一个不可以组成单词的字符,如[\W]匹配"$5.98"中的$,等于[^a-zA-Z0-9]。
代码
/**
* @param {string[]} words
* @return {string[]}
*/
var findWords = function (words) {
return words.filter(x => /(^[qwertyuiop]+$)|(^[asdfghjkl]+$)|(^[zxcvbnm]+$)/i.test(x))
};
03.reduce方法
01.使用详解
1、语法
arr.reduce(callback,[initialValue])
reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 reduce 的数组。
callback (执行数组中每个值的函数,包含四个参数) 1、previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue)) 2、currentValue (数组中当前被处理的元素) 3、index (当前元素在数组中的索引) 4、array (调用 reduce 的数组) initialValue (作为第一次调用 callback 的第一个参数。)
2、实例解析 initialValue 参数
先看第一个例子
var arr = [1, 2, 3, 4]; var sum = arr.reduce(function(prev, cur, index, arr) { console.log(prev, cur, index); return prev + cur; }) console.log(arr, sum);
打印结果:
1 2 1
3 3 2
6 4 3
[1, 2, 3, 4] 10这里可以看出,上面的例子index是从1开始的,第一次的prev的值是数组的第一个值。数组长度是4,但是reduce函数循环3次。
再看第二个例子:
var arr = [1, 2, 3, 4]; var sum = arr.reduce(function(prev, cur, index, arr) { console.log(prev, cur, index); return prev + cur; },0) //注意这里设置了初始值 console.log(arr, sum);
打印结果:
0 1 0
1 2 1
3 3 2
6 4 3
[1, 2, 3, 4] 10这个例子index是从0开始的,第一次的prev的值是我们设置的初始值0,数组长度是4,reduce函数循环4次。
结论:
如果没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue,从索引0开始。
注意:如果这个数组为空,运用reduce是什么情况?
var arr = []; var sum = arr.reduce(function(prev, cur, index, arr) { console.log(prev, cur, index); return prev + cur; }) //报错,"TypeError: Reduce of empty array with no initial value"
但是要是我们设置了初始值就不会报错,如下:
var arr = []; var sum = arr.reduce(function(prev, cur, index, arr) { console.log(prev, cur, index); return prev + cur; },0) console.log(arr, sum); // [] 0
所以一般来说我们提供初始值通常更安全
3、reduce的简单用法
当然最简单的就是我们常用的数组求和,求乘积了。
var arr = [1, 2, 3, 4]; var sum = arr.reduce((x,y)=>x+y) var mul = arr.reduce((x,y)=>x*y) console.log( sum ); //求和,10 console.log( mul ); //求乘积,24
4、reduce的高级用法
(1)计算数组中每个元素出现的次数
let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice']; let nameNum = names.reduce((pre,cur)=>{ if(cur in pre){ pre[cur]++ }else{ pre[cur] = 1 } return pre },{}) console.log(nameNum); //{Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}
(2)数组去重
let arr = [1,2,3,4,4,1] let newArr = arr.reduce((pre,cur)=>{ if(!pre.includes(cur)){ return pre.concat(cur) }else{ return pre } },[]) console.log(newArr);// [1, 2, 3, 4]
(3)将二维数组转化为一维
let arr = [[0, 1], [2, 3], [4, 5]] let newArr = arr.reduce((pre,cur)=>{ return pre.concat(cur) },[]) console.log(newArr); // [0, 1, 2, 3, 4, 5]
(3)将多维数组转化为一维
let arr = [[0, 1], [2, 3], [4,[5,6,7]]] const newArr = function(arr){ return arr.reduce((pre,cur)=>pre.concat(Array.isArray(cur)?newArr(cur):cur),[]) } console.log(newArr(arr)); //[0, 1, 2, 3, 4, 5, 6, 7]
(4)、对象里的属性求和
var result = [ { subject: 'math', score: 10 }, { subject: 'chinese', score: 20 }, { subject: 'english', score: 30 } ]; var sum = result.reduce(function(prev, cur) { return cur.score + prev; }, 0); console.log(sum) //60
02.典型例题
682. 棒球比赛
01.题目
你现在是一场采用特殊赛制棒球比赛的记录员。这场比赛由若干回合组成,过去几回合的得分可能会影响以后几回合的得分。
比赛开始时,记录是空白的。你会得到一个记录操作的字符串列表 ops,其中 ops[i] 是你需要记录的第 i 项操作,ops 遵循下述规则:
整数 x - 表示本回合新获得分数 x
"+" - 表示本回合新获得的得分是前两次得分的总和。题目数据保证记录此操作时前面总是存在两个有效的分数。
"D" - 表示本回合新获得的得分是前一次得分的两倍。题目数据保证记录此操作时前面总是存在一个有效的分数。
"C" - 表示前一次得分无效,将其从记录中移除。题目数据保证记录此操作时前面总是存在一个有效的分数。
请你返回记录中所有得分的总和。
示例 1:
输入:ops = ["5","2","C","D","+"]
输出:30
解释:
"5" - 记录加 5 ,记录现在是 [5]
"2" - 记录加 2 ,记录现在是 [5, 2]
"C" - 使前一次得分的记录无效并将其移除,记录现在是 [5].
"D" - 记录加 2 * 5 = 10 ,记录现在是 [5, 10].
"+" - 记录加 5 + 10 = 15 ,记录现在是 [5, 10, 15].
所有得分的总和 5 + 10 + 15 = 30
示例 2:
输入:ops = ["5","-2","4","C","D","9","+","+"]
输出:27
解释:
"5" - 记录加 5 ,记录现在是 [5]
"-2" - 记录加 -2 ,记录现在是 [5, -2]
"4" - 记录加 4 ,记录现在是 [5, -2, 4]
"C" - 使前一次得分的记录无效并将其移除,记录现在是 [5, -2]
"D" - 记录加 2 * -2 = -4 ,记录现在是 [5, -2, -4]
"9" - 记录加 9 ,记录现在是 [5, -2, -4, 9]
"+" - 记录加 -4 + 9 = 5 ,记录现在是 [5, -2, -4, 9, 5]
"+" - 记录加 9 + 5 = 14 ,记录现在是 [5, -2, -4, 9, 5, 14]
所有得分的总和 5 + -2 + -4 + 9 + 5 + 14 = 27
示例 3:
输入:ops = ["1"]
输出:1
02.题解
// /**
// * @param {string[]} ops
// * @return {number}
// */
var calPoints = function(ops) {
var sum = 0;
var res = []
ops.forEach(item=>{
if(item==='+'){
res.push(+res[res.length-1]+res[res.length-2])
}else if(item==='D'){
res.push(+res[res.length-1] * 2)
}else if(item==='C'){
res.pop()
}else{
res.push(+item)
}
})
return res.reduce((total,item)=>total+item)
};
04.entries
Object.entries()
作用:返回的是一个数组,返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for…in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环也枚举原型链中的属性)。Object.entries()返回一个数组,其元素是与直接在object上找到的可枚举属性键值对相对应的数组。属性的顺序与通过手动循环对象的属性值所给出的顺序相同。
语法:
Object.entries(obj)
- 参数:obj可以返回其可枚举属性的键值对的对象。
- 返回值:给定对象自身可枚举属性的键值对数组。
实例:
let person={name:'lisa',age:12,adress:'北京',show:function(){}}; console.log(Object.entries(person));
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x6llfeDd-1629886228977)(20191112111221804.png)]
上述例子返回的是一个二维数组。因为返回的格式很像Map,所以我们可以把它改成Map格式,如下:
var obj={name:"lisa",age:12}; var m=new Map(Object.entries(obj)); console.log(m);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pO7gB8o5-1629886228980)(20191112111531310.png)]
Object.fromEntries()
作用:该方法把键值对列表转换为一个对象。
Object.fromEntries() 是 Object.entries 的反转。语法
Object.fromEntries(iterable);
- 参数 iterable:可迭代对象,类似 Array 、 Map 或者其它实现了可迭代协议的对象。
- 返回值:一个由该迭代对象条目提供对应属性的新对象。
实例
let a=new Map([['name','张三'],['age','12'],['address','北京']]); let b=Object.fromEntries(a); console.log(b);
数组entries()
作用:
返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对。语法
arr.entries()
返回值:
一个新的 Array 迭代器对象。Array Iterator是对象,它的原型(__
proto__
:Array Iterator)上有一个next方法,可用用于遍历迭代器取得原数组的[key,value]。实例
let arr=["red","yellow","orange","pink"]; let i=arr.entries(); console.log(i.next().value); console.log(i.next().value);
可以使用for…of循环entries()
let arr=["red","yellow","orange","pink"]; let i=arr.entries(); for(let e of i) { console.log(e); }
04.Map 实例的遍历方法
keys():返回键名的遍历器。
values():返回键值的遍历器。
entries():返回所有成员的遍历器。
forEach():遍历 Map 的所有成员。
const map = new Map(); map.set('aaa', 100); map.set('bbb', 200); for (let key of map.keys()) { console.log(key); } // "aaa" // "bbb" for (let value of map.values()) { console.log(value); } // 100 // 200 for (let item of map.entries()) { console.log(item[0], item[1]); } // aaa 100 //...
05.map
定义和用法
map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
map() 方法按照原始数组元素顺序依次处理元素。
注意: map() 不会对空数组进行检测。
注意: map() 不会改变原始数组。
//实例 //返回一个数组,数组中元素为原始数组的平方根: var numbers = [4, 9, 16, 25]; function myFunction() { x = document.getElementById("demo") x.innerHTML = numbers.map(Math.sqrt); } //输出结果为: //2,3,4,5
[‘1‘,‘2‘,‘3‘].map(parseInt)结果讲解
一、前言
这是一道前端面试题,先说结果:[1, NaN, NaN]二、为什么会是这个结果
- map函数
将数组的每个元素传递给指定的函数处理,并返回处理后的数组,所以 [‘1’,‘2’,‘3’].map(parseInt) 就是将字符串1,2,3作为元素;0,1,2作为下标分别调用 parseInt 函数。即分别求出 parseInt(‘1’,0), parseInt(‘2’,1), parseInt(‘3’,2)的结果。
- parseInt函数(重点)
概念:以第二个参数为基数来解析第一个参数字符串,通常用来做十进制的向上取整(省略小数)如:parseInt(2.7) //结果为2
特点:接收两个参数parseInt(string,radix)
string:字母(大小写均可)、数组、特殊字符(不可放在开头,特殊字符及特殊字符后面的内容不做解析)的任意字符串,如 ‘2’、‘2w’、‘2!’
radix:解析字符串的基数,基数规则如下:
1) 区间范围介于2~36之间;
2 ) 当参数为 0,parseInt() 会根据十进制来解析;
3 ) 如果忽略该参数,默认的基数规则:
如果 string 以 "0x" 开头,parseInt() 会把 string 的其余部分解析为十六进制的整数;parseInt("0xf") //15 如果 string 以 0 开头,其后的字符解析为八进制或十六进制的数字;parseInt("08") //8 如果 string 以 1 ~ 9 的数字开头,parseInt() 将把它解析为十进制的整数;parseInt("88.99f") //88 只有字符串中的第一个数字会被返回。parseInt("10.33") //返回10; 开头和结尾的空格是允许的。parseInt(" 69 10 ") //返回69 如果字符串的第一个字符不能被转换为数字,返回 NaN。parseInt("f") //返回NaN 而parseInt("f",16) //返回15
三、再来分析一下结果
[‘1’,‘2’,‘3’].map(parseInt)即parseInt(‘1’,0);radix 为 0,parseInt() 会根据十进制来解析,所以结果为 1;
parseInt(‘2’,1);radix 为 1,超出区间范围,所以结果为 NaN;
parseInt(‘3’,2);radix 为 2,用2进制来解析,应以 0 和 1 开头,所以结果为 NaN。
四、parseInt方法解析的运算过程
parseInt(‘101.55’,10); //以十进制解析,运算过程:向上取整数(不做四舍五入,省略小数),结果为 101。parseInt(‘101’,2); //以二进制解析,运算过程:12的2次方+02的1次方+1*2的0次方=4+0+1=5,结果为 5。
parseInt(‘101’,8); //以八进制解析,运算过程:18的2次方+08的1次方+1*8的0次方=64+0+1=65,结果为 65。
parseInt(‘101’,16); //以十六进制解析,运算过程:116的2次方+016的1次方+1*16的0次方=256+0+1=257,结果为 257
典型例题
我们要把给定的字符串 S 从左到右写到每一行上,每一行的最大宽度为100个单位,如果我们在写某个字母的时候会使这行超过了100 个单位,那么我们应该把这个字母写到下一行。我们给定了一个数组 widths ,这个数组 widths[0] 代表 'a' 需要的单位, widths[1] 代表 'b' 需要的单位,..., widths[25] 代表 'z' 需要的单位。 现在回答两个问题:至少多少行能放下S,以及最后一行使用的宽度是多少个单位?将你的答案作为长度为2的整数列表返回。 示例 1: 输入: widths = [10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10] S = "abcdefghijklmnopqrstuvwxyz" 输出: [3, 60] 解释: 所有的字符拥有相同的占用单位10。所以书写所有的26个字母, 我们需要2个整行和占用60个单位的一行。 示例 2: 输入: widths = [4,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10] S = "bbbcccdddaaa" 输出: [2, 4] 解释: 除去字母'a'所有的字符都是相同的单位10,并且字符串 "bbbcccdddaa" 将会覆盖 9 * 10 + 2 * 4 = 98 个单位. 最后一个字母 'a' 将会被写到第二行,因为第一行只剩下2个单位了。 所以,这个答案是2行,第二行有4个单位宽度。
1.将单词中的每一个字母转换成对应的数字 2.定义两个变量,用来存储行数,和最后的余数 3.逢百进1,默认就有一行
/** * @param {number[]} widths * @param {string} s * @return {number[]} */ var numberOfLines = function(widths, s) { const sList = s.split("").map(item=>{ return widths[item.charCodeAt() - 97] }) let counts = 1 let summary = 0 // console.log("sList:", sList) for(j=0;j < sList.length ;j++) { const item = sList[j] // const nextItem = sList[j-1] if (summary + item <= 100 ) { summary += item } else { counts += 1 summary = item } } return [counts,summary] };
06.every和some
every()与some()方法都是JS中数组的迭代方法。
every()是对数组中每一项运行给定函数,如果该函数对每一****项返回true,则返回true。
some()是对数组中每一项运行给定函数,如果该函数对任一****项返回true,则返回true。
-
总结:
方法区别
every() 每一项都返回true才返回true 找到最终结构就停止
some() 只要有一项返回true就返回true 找到最终结构就停止
var arr = [ 1, 2, 3, 4, 5, 6 ];
console.log( arr.some( function( item, index, array ){
console.log( 'item=' + item + ',index='+index+',array='+array );
return item > 3;
}));
//output-->>
// item=1,index=0,array=1,2,3,4,5,6
// item=2,index=1,array=1,2,3,4,5,6
// item=3,index=2,array=1,2,3,4,5,6
// item=4,index=3,array=1,2,3,4,5,6
// true
console.log( arr.every( function( item, index, array ){
console.log( 'item=' + item + ',index='+index+',array='+array );
return item > 3;
}));
//output-->>
// item=1,index=0,array=1,2,3,4,5,6
// false
实例1 every判断单调序列 有一个不满足则返回false 注意 如果有一个元素不返回值 自动返回false
/**
* @param {number[]} nums
* @return {boolean}
*/
var isMonotonic = function(nums) {
return nums.every((item,index)=>{
if(index<nums.length-1){
if(nums[0]>=nums[nums.length-1]){
if(item>=nums[index+1]){
return true
}else{
console.log('有元素失败',index)
return false
}
}
if(nums[0]<=nums[nums.length-1]){
if(item<=nums[index+1]){
return true
}else{
return false
}
}
}else{
return true
}
}
)
};
cript
/**
-
@param {number[]} nums
-
@return {boolean}
*/
var isMonotonic = function(nums) {return nums.every((item,index)=>{
if(index<nums.length-1){
if(nums[0]>=nums[nums.length-1]){
if(item>=nums[index+1]){
return true
}else{
console.log(‘有元素失败’,index)
return false
}
}
if(nums[0]<=nums[nums.length-1]){
if(item<=nums[index+1]){
return true
}else{
return false
}
}
}else{
return true
}} )
};