,
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
给你一个排序后的字符列表 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() 不会改变原始数组。
利用 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 的数组。
```css callback (执行数组中每个值的函数,包含四个参数)
1、previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue))
2、currentValue (数组中当前被处理的元素)
3、index (当前元素在数组中的索引)
4、array (调用 reduce 的数组)
initialValue (作为第一次调用 callback 的第一个参数。)
> > <a name="fd2860c6"></a>
#### 2、实例解析 initialValue 参数
> 先看第一个例子
> ```jsx
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)计算数组中每个元素出现的次数
```jsx 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)数组去重
> ```jsx
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)、对象里的属性求和
```jsx 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
神奇写法 提前使用
<a name="0824b16b-1"></a>
### 02.典型例题
<a name="b01e337d"></a>
#### [682. 棒球比赛](https://leetcode-cn.com/problems/baseball-game/)
<a name="ba515c95"></a>
##### 01.题目
```css
你现在是一场采用特殊赛制棒球比赛的记录员。这场比赛由若干回合组成,过去几回合的得分可能会影响以后几回合的得分。
比赛开始时,记录是空白的。你会得到一个记录操作的字符串列表 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)
};
905. 按奇偶排序数组
给定一个非负整数数组 A,返回一个数组,在该数组中, A 的所有偶数元素之后跟着所有奇数元素。
你可以返回满足此条件的任何数组作为答案。
示例:
输入:[3,1,2,4]
输出:[2,4,3,1]
输出 [4,2,3,1],[2,4,1,3] 和 [4,2,1,3] 也会被接受。
提示:
1 <= A.length <= 5000
0 <= A[i] <= 5000
扁平化
解题思路
二维数组,0位数组放偶数,1位数字放奇数。扁平化
var sortArrayByParity = function(A) {
//注意 此处写法用到了剪头函数强行不写大括号 (item,index)=>(操作1,操作2,操作3,返回值)
return A.reduce((p, v)=> (p[v & 1].push(v), p) , [[], []]).flat()
};
遍历 偶数放前面 奇数放后面 +reduce
/**
* @param {number[]} nums
* @return {number[]}
*/
var sortArrayByParity = function(nums) {
// return nums.reduce((p, v)=> (p[v & 1].push(v), p) , [[], []]).flat()
// return nums.reduce((p, v)=> (p[v & 1].push(v),console.log(123), p) , [[], []]).flat()
return nums.reduce((p,v)=>{
v & 1 ? p.push(v) : p.unshift(v)
return p
},[])
};
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));
上述例子返回的是一个二维数组。因为返回的格式很像Map,所以我们可以把它改成Map格式,如下:
var obj={name:"lisa",age:12};
var m=new Map(Object.entries(obj));
console.log(m);
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 的所有成员。 ```javascript 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 //…
```javascript
entries()实例:
var arr = ["a", "b", "c"];
var eArr = arr.entries();
console.log(eArr.next().value); // [0, "a"]
console.log(eArr.next().value); // [1, "b"]
console.log(eArr.next().value); // [2, "c"]
05.map
定义和用法 ——-输入一个数组 返回一个操作后的数组
map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
map() 方法按照原始数组元素顺序依次处理元素。
注意: map() 不会对空数组进行检测。
注意: map() 不会改变原始数组。
```javascript //实例 //返回一个数组,数组中元素为原始数组的平方根:
var numbers = [4, 9, 16, 25];
function myFunction() { x = document.getElementById(“demo”) x.innerHTML = numbers.map(Math.sqrt); }
//输出结果为: //2,3,4,5
> ```javascript
//实用实例
let books = [{
name: "《算法导论》",
beginDate: "2006-9",
price: 85.00,
count: 1
},
{
name: "《UNIX编程艺术》",
beginDate: "2006-2",
price: 59.00,
count: 1
},
{
name: "《编程大全》",
beginDate: "2008-10",
price: 39.00,
count: 1
},
{
name: "《代码大全》",
beginDate: "2006-3",
price: 128.00,
count: 1
},
]
let result = books.map(item => {
return item.price * item.count
})
console.log(result);
//输出结果为:
//[ 85, 59, 39, 128 ]
MDN web docs上面说:
map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
并举了个例子:
var array1 = [1,4,9,16];
const map1 = array1.map(x => x *2);
console.log(map1);//[2,8,18,32]
打印结果为:
Array [2,8,18,32]
而我这样写时:
```javascript var array1 = [1, 4, 9, 16];
const map1 = array1.map(x => { if (x == 4) { return x * 2; } });
console.log(map1);
> 打印结果为:
>
> ```javascript
Array [undefined, 8, undefined, undefined]
为什么会出现三个undefined呢?而不是我预期的[1,8,9,16]。
这样写只是增加了一个条件,即x的值为4时才乘以2,之所以会出现undefined,是因为map()方法创建了一个新数组,但新数组并不是在遍历完array1后才被赋值的,而是每遍历一次就得到一个值。所以,下面这样修改后就正确了:
```javascript var array1 = [1, 4, 9, 16];
const map1 = array1.map(x => { if (x == 4) { return x * 2; } return x; });
> > <a name="2e78b2f0"></a>
# [‘1‘,‘2‘,‘3‘].map(parseInt)结果讲解
> > 一、前言<br />
这是一道前端面试题,先说结果:[1, NaN, NaN]
> 二、为什么会是这个结果
> 1. map函数
>
将数组的每个元素传递给指定的函数处理,并返回处理后的数组,所以 ['1','2','3'].map(parseInt) 就是将字符串1,2,3作为元素;0,1,2作为下标分别调用 parseInt 函数。即分别求出 parseInt('1',0), parseInt('2',1), parseInt('3',2)的结果。
> 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
> 三、再来分析一下结果<br />
['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方法解析的运算过程<br />
parseInt('101.55',10); //以十进制解析,运算过程:向上取整数(不做四舍五入,省略小数),结果为 101。
> parseInt('101',2); //以二进制解析,运算过程:1_2的2次方+0_2的1次方+1*2的0次方=4+0+1=5,结果为 5。
> parseInt('101',8); //以八进制解析,运算过程:1_8的2次方+0_8的1次方+1*8的0次方=64+0+1=65,结果为 65。
> parseInt('101',16); //以十六进制解析,运算过程:1_16的2次方+0_16的1次方+1*16的0次方=256+0+1=257,结果为 257
> > <a name="c5627a9d"></a>
## 典型例题
> ```css
我们要把给定的字符串 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,默认就有一行
```javascript /**
- @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]
};
<a name="d01c5e7d"></a>
## 06.every和some
[JS中every()和some()的用法](https://www.cnblogs.com/yourstars/p/7822858.html)
every()与some()方法都是JS中数组的迭代方法。
every()是对数组中每一项运行给定函数,如果该函数对**每一项**返回true,才返回true。 有意一项不满足。返回false
some()是对数组中每一项运行给定函数,如果该函数对**任一项**返回true,就返回true。
```css
some() 方法会对数组中的每一项进行遍历,只要有一个元素符合条件,就返回true,且==剩余的元素不会再进行检测==,否则就返回false。
every() 方法会对数组中的每一项进行遍历,只有所有元素都符合条件时,才返回true,如果数组中检测到有一个元素不满足,则整个表达式返回 false ,且==剩余的元素不会再进行检测==。 如果有一个元素不返回值 自动返回false
- 总结:
方法区别
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
}
}
)
};
典型例题01.211. 添加与搜索单词 - 数据结构设计
```css 请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。
实现词典类 WordDictionary :
WordDictionary() 初始化词典对象 void addWord(word) 将 word 添加到数据结构中,之后可以对它进行匹配 bool search(word) 如果数据结构中存在字符串与 word 匹配,则返回 true ;否则,返回 false 。word 中可能包含一些 ‘.’ ,每个 . 都可以表示任何一个字母。
示例:
输入: [“WordDictionary”,”addWord”,”addWord”,”addWord”,”search”,”search”,”search”,”search”] [[],[“bad”],[“dad”],[“mad”],[“pad”],[“bad”],[“.ad”],[“b..”]] 输出: [null,null,null,null,false,true,true,true]
解释: WordDictionary wordDictionary = new WordDictionary(); wordDictionary.addWord(“bad”); wordDictionary.addWord(“dad”); wordDictionary.addWord(“mad”); wordDictionary.search(“pad”); // return False wordDictionary.search(“bad”); // return True wordDictionary.search(“.ad”); // return True wordDictionary.search(“b..”); // return True
提示:
1 <= word.length <= 500 addWord 中的 word 由小写英文字母组成 search 中的 word 由 ‘.’ 或小写英文字母组成 最多调用 50000 次 addWord 和 search
> 方法1 使用数组封装
> ```javascript
var WordDictionary = function() {
this.item = []
};
/**
* @param {string} word
* @return {void}
*/
WordDictionary.prototype.addWord = function(word) {
this.item.push(word)
};
/**
* @param {string} word
* @return {boolean}
*/
WordDictionary.prototype.search = function(word) {
return this.item.some(element=>{//some 有一个符合条件即返回true 否则遍历全部数据后返回false
if(element === word){
return true
}else{
if(element.length==word.length){
return element.split('').every((char,index)=>{//every 全部符合条件才返回true
return char===word[index] || word[index]=== '.'
})
}else{
return false
}
}
})
};
/**
* Your WordDictionary object will be instantiated and called as such:
* var obj = new WordDictionary()
* obj.addWord(word)
* var param_2 = obj.search(word)
*/
02.常用语句
01.快速求取数组最大值
let array = [1,2,3]
Math.max(...array)
03.白嫖笔记
今天我们来看点基础的知识,看看JavaScript中有些循环遍历方法:
一、数组遍历方法
1. forEach()
forEach
方法用于调用数组的每个元素,并将元素传递给回调函数。数组中的每个值都会调用回调函数。其语法如下:
array.forEach(function(currentValue, index, arr), thisValue)
该方法的第一个参数为回调函数,是必传的,它有三个参数:
currentValue:必需。当前元素
index:可选。当前元素的索引值。
arr:可选。当前元素所属的数组对象
let arr = [1,2,3,4,5]
arr.forEach((item, index, arr) => {
console.log(index+":"+item)
})
该方法还可以有第二个参数,用来绑定回调函数内部this变量(前提是回调函数不能是箭头函数,因为箭头函数没有this):
let arr = [1,2,3,4,5]
let arr1 = [9,8,7,6,5]
arr.forEach(function(item, index, arr){
console.log(this[index]) // 9 8 7 6 5
}, arr1)
注意:
forEach 方法不会改变原数组,也没有返回值;
forEach无法使用 break,continue 跳出循环,使用 return 时,效果和在 for 循环中使用 continue 一致;
forEach 方法无法遍历对象,仅适用于数组的遍历。
2. map()
map()
方法会返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。该方法按照原始数组元素顺序依次处理元素。其语法如下:
array.map(function(currentValue,index,arr), thisValue)
该方法的第一个参数为回调函数,是必传的,它有三个参数:
currentValue:必须。当前元素的值;
index:可选。当前元素的索引值;
arr:可选。当前元素属于的数组对象。
let arr = [1, 2, 3];
arr.map(item => {
return item + 1;
})
// 输出结果: [2, 3, 4]
该方法的第二个参数用来绑定参数函数内部的this变量,是可选的:
let arr = ['a', 'b', 'c'];
[1, 2].map(function (e) {
return this[e];
}, arr)
// 输出结果: ['b', 'c']
该方法还可以进行链式调用:
let arr = [1, 2, 3];
arr.map(item => item + 1).map(item => item + 1)
// 输出结果: [3, 4, 5]
注意:
map 方法不会对空数组进行检测;
map 方法遍历数组时会返回一个新数组,不会改变原始数组;
map 方法有返回值,可以return出来,map的回调函数中支持return返回值;
map 方法无法遍历对象,仅适用于数组的遍历。
3. for of
for...of
语句创建一个循环来迭代可迭代的对象。在 ES6 中引入的 for...of
循环,以替代 for...in
和 forEach()
,并支持新的迭代协议。其语法如下:
for (variable of iterable) {
statement
}
该方法有两个参数:
- variable:每个迭代的属性值被分配给该变量。
- iterable:一个具有可枚举属性并且可以迭代的对象。
该方法允许获取对象的键值:
let arr = [
{id:1, value:'hello'},
{id:2, value:'world'},
{id:3, value:'JavaScript'}
]
for (let item in arr) {
console.log(item);
}
// 输出结果:0 1 2
注意:
for of 方法只会遍历当前对象的属性,不会遍历其原型链上的属性;
for of 方法适用遍历 数组/ 类数组/字符串/map/set 等拥有迭代器对象的集合;
for of 方法不支持遍历普通对象,因为其没有迭代器对象。如果想要遍历一个对象的属性,可以用 for in 方法;
可以使用break、continue、return来中断循环遍历;
4. filter()
filter不会修改原数组
filter()
方法用于过滤数组,满足条件的元素会被返回。它的参数是一个回调函数,所有数组元素依次执行该函数,返回结果为true的元素会被返回,如果没有符合条件的元素,则返回空数组。其语法如下:
array.filter(function(currentValue,index,arr), thisValue)
该方法的第一个参数为回调函数,是必传的,它有三个参数:
currentValue:必须。当前元素的值;
index:可选。当前元素的索引值;
arr:可选。当前元素属于的数组对象。
const arr = [1, 2, 3, 4, 5]
arr.filter(item => item > 2)
// 输出结果:[3, 4, 5]
同样,它也有第二个参数,用来绑定参数函数内部的this变量。
可以使用filter()
方法来移除数组中的undefined、null、NAN等值:
let arr = [1, undefined, 2, null, 3, false, '', 4, 0]
arr.filter(Boolean)
// 输出结果:[1, 2, 3, 4]
注意:
filter 方法会返回一个新的数组,不会改变原数组;
filter 方法不会对空数组进行检测;
filter 方法仅适用于检测数组。
5. some()、every()
some() 方法会对数组中的每一项进行遍历,只要有一个元素符合条件,就返回true,且剩余的元素不会再进行检测,否则就返回false。
every() 方法会对数组中的每一项进行遍历,只有所有元素都符合条件时,才返回true,如果数组中检测到有一个元素不满足,则整个表达式返回 false ,且剩余的元素不会再进行检测。其语法如下:
两者的语法如下:
array.some(function(currentValue,index,arr),thisValue)
array.every(function(currentValue,index,arr), thisValue)
两个方法的第一个参数为回调函数,是必传的,它有三个参数:
currentValue:必须。当前元素的值;
index:可选。当前元素的索引值;
arr:可选。当前元素属于的数组对象。
let arr = [1, 2, 3, 4, 5]
arr.some(item => item > 4)
// 输出结果: true
let arr = [1, 2, 3, 4, 5]
arr.every(item => item > 0)
// 输出结果: true
注意:
两个方法都不会改变原数组,会返回一个布尔值;
两个方法都不会对空数组进行检测;
两个方法都仅适用于检测数组。
6. reduce()、reduceRight()
reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。reduce() 可以作为一个高阶函数,用于函数的 compose。其语法如下:
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
reduce 方法会为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,回调函数接受四个参数:
total:上一次调用回调返回的值,或者是提供的初始值(initialValue);
currentValue:当前被处理的元素;
currentIndex:当前元素的索引;
arr:当前元素所属的数组对象。
该方法的第二个参数是 initialValue
,表示传递给函数的初始值 (作为第一次调用 callback 的第一个参数):
let arr = [1, 2, 3, 4]
let sum = arr.reduce((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
再来加一个初始值试试:
let arr = [1, 2, 3, 4]
let sum = arr.reduce((prev, cur, index, arr) => {
console.log(prev, cur, index);
return prev + cur;
}, 5)
console.log(arr, sum);
输出结果:
5 1 0
6 2 1
8 3 2
11 4 3
[1, 2, 3, 4] 15
由此可以得出结论:如果没有提供初始值initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供了初始值initialValue,从索引0开始执行
reduceRight() 方法和的reduce()
用法几乎一致,只是该方法是对数组进行倒序遍历的,而reduce()
方法是正序遍历的。
let arr = [1, 2, 3, 4]
let sum = arr.reduceRight((prev, cur, index, arr) => {
console.log(prev, cur, index);
return prev + cur;
}, 5)
console.log(arr, sum);
输出结果:
5 4 3
9 3 2
12 2 1
14 1 0
[1, 2, 3, 4] 15
注意:
两个方法都不会改变原数组;
两个方法如果添加初始值,就会改变原数组,会将这个初始值放在数组的最后一位;
两个方法对于空数组是不会执行回调函数的。
7. find()、findIndex()
find()
方法返回通过函数内判断的数组的第一个元素的值。当数组中的元素在测试条件时返回 true 时, find()
返回符合条件的元素,之后的值不会再调用执行函数。如果没有符合条件的元素返回 undefined。
findIndex()
方法返回传入一个测试函数符合条件的数组第一个元素位置(索引)。当数组中的元素在函数条件时返回 true 时, findIndex()
返回符合条件的元素的索引位置,之后的值不会再调用执行函数。如果没有符合条件的元素返回 -1。
两个方法的语法如下:
array.find(function(currentValue, index, arr),thisValue)
array.findIndex(function(currentValue, index, arr), thisValue)
两个方法的第一个参数为回调函数,是必传的,它有三个参数:
currentValue:必需。当前元素;
index:可选。当前元素的索引;
arr:可选。当前元素所属的数组对象。
let arr = [1, 2, 3, 4, 5]
arr.find(item => item > 2)
// 输出结果: 3
let arr = [1, 2, 3, 4, 5]
arr.findIndex(item => item > 2)
// 输出结果: 2
find()
和findIndex()
两个方法几乎一样,只是返回结果不同:
find()
:返回的是第一个符合条件的值;findIndex
:返回的是第一个返回条件的值的索引值。
注意:
- 两个方法对于空数组,函数是不会执行的;
- 两个方法否不会改变原数组。
8. keys()、values()、entries()
三个方法都返回一个数组的迭代对象,对象的内容不太相同:
keys() 返回数组的索引值;
values() 返回数组的元素;
entries() 返回数组的键值对。
三个方法的语法如下:
array.keys()
array.values()
array.entries()
这三个方法都没有参数:
let arr = ["Banana", "Orange", "Apple", "Mango"];
const iterator1 = arr.keys();
const iterator2 = arr.values()
const iterator3 = arr.entries()
for (let item of iterator1) {
console.log(item);
}
// 输出结果: 0 1 2 3
for (let item of iterator2) {
console.log(item);
}
// 输出结果: Banana Orange Apple Mango
for (let item of iterator3) {
console.log(item);
}
// 输出结果:[0, 'Banana'] [1, 'Orange'] [2, 'Apple'] [3, 'Mango']
总结:
方法 | 是否改变原数组 | 特点 |
---|---|---|
forEach() | 否 | 没有返回值 |
map() | 否 | 有返回值,可链式调用 |
for of | 否 | for…of遍历具有Iterator迭代器的对象的属性,返回的是数组的元素、对象的属性值,不能遍历普通的obj对象,将异步循环变成同步循环 |
filter() | 否 | 过滤数组,返回包含符合条件的元素的数组,可链式调用 |
every()、some() | 否 | some()只要有一个是true,便返回true;而every()只要有一个是false,便返回false. |
find()、findIndex() | 否 | find()返回的是第一个符合条件的值;findIndex()返回的是第一个返回条件的值的索引值 |
reduce()、reduceRight() | 否 | reduce()对数组正序操作;reduceRight()对数组逆序操作 |
keys()、values()、entries() | 否 | keys() 返回数组的索引值;values() 返回数组元素;entries() 返回数组的键值对。 |
二、对象遍历方法
1. for in
for…in
主要用于循环对象属性。循环中的代码每执行一次,就会对对象的属性进行一次操作。其语法如下:
for (var in object) {
执行的代码块
}
其中两个参数:
- var:必须。指定的变量可以是数组元素,也可以是对象的属性。
- object:必须。指定迭代的的对象。
var obj = {a: 1, b: 2, c: 3};
for (var i in obj) {
console.log('键名:', i);
console.log('键值:', obj[i]);
}
输出结果:
键名: a
键值: 1
键名: b
键值: 2
键名: c
键值: 3
注意:
- for in 方法不仅会遍历当前的对象所有的可枚举属性,还会遍历其原型链上的属性。
2. Object.keys()、Object.values()、Object.entries()
这三个方法都用来遍历对象,它会返回一个由给定对象的自身可枚举属性(不含继承的和Symbol属性)组成的数组,数组元素的排列顺序和正常循环遍历该对象时返回的顺序一致,这个三个元素返回的值分别如下:
Object.keys():返回包含对象键名的数组;
Object.values():返回包含对象键值的数组;
Object.entries():返回包含对象键名和键值的数组。
let obj = {
id: 1,
name: 'hello',
age: 18
};
console.log(Object.keys(obj)); // 输出结果: ['id', 'name', 'age']
console.log(Object.values(obj)); // 输出结果: [1, 'hello', 18]
console.log(Object.keys(obj)); // 输出结果: [['id', 1], ['name', 'hello'], ['age', 18]
注意
- Object.keys()方法返回的数组中的值都是字符串,也就是说不是字符串的key值会转化为字符串。
- 结果数组中的属性值都是对象本身可枚举的属性,不包括继承来的属性。
3. Object.getOwnPropertyNames()
Object.getOwnPropertyNames()
方法与Object.keys()
类似,也是接受一个对象作为参数,返回一个数组,包含了该对象自身的所有属性名。但它能返回不可枚举的属性。
let a = ['Hello', 'World'];
Object.keys(a) // ["0", "1"]
Object.getOwnPropertyNames(a) // ["0", "1", "length"]
这两个方法都可以用来计算对象中属性的个数:
var obj = { 0: "a", 1: "b", 2: "c"};
Object.getOwnPropertyNames(obj) // ["0", "1", "2"]
Object.keys(obj).length // 3
Object.getOwnPropertyNames(obj).length // 3
4. Object.getOwnPropertySymbols()
Object.getOwnPropertySymbols()
方法返回对象自身的 Symbol 属性组成的数组,不包括字符串属性:
let obj = {a: 1}
// 给对象添加一个不可枚举的 Symbol 属性
Object.defineProperties(obj, {
[Symbol('baz')]: {
value: 'Symbol baz',
enumerable: false
}
})
// 给对象添加一个可枚举的 Symbol 属性
obj[Symbol('foo')] = 'Symbol foo'
Object.getOwnPropertySymbols(obj).forEach((key) => {
console.log(obj[key])
})
// 输出结果:Symbol baz Symbol foo
5. Reflect.ownKeys()
Reflect.ownKeys() 返回一个数组,包含对象自身的所有属性。它和Object.keys()类似,Object.keys()返回属性key,但不包括不可枚举的属性,而Reflect.ownKeys()会返回所有属性key:
var obj = {
a: 1,
b: 2
}
Object.defineProperty(obj, 'method', {
value: function () {
alert("Non enumerable property")
},
enumerable: false
})
console.log(Object.keys(obj))
// ["a", "b"]
console.log(Reflect.ownKeys(obj))
// ["a", "b", "method"]
注意:
- Object.keys() :相当于返回对象属性数组;
- Reflect.ownKeys() :相当于
Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertySymbols(obj)
。
总结:
对象方法 | 遍历基本属性 | 遍历原型链 | 遍历不可枚举属性 | 遍历Symbol |
---|---|---|---|---|
for in | 是 | 是 | 否 | 否 |
Object.keys() | 是 | 否 | 否 | 否 |
Object.getOwnPropertyNames() | 是 | 否 | 是 | 否 |
Object.getOwnPropertySymbols() | 否 | 否 | 是 | 是 |
Reflect.ownKeys() | 是 | 否 | 是 | 是 |
三、其他遍历方法
1. for
for循环是应该是最常见的循环方式了,它由三个表达式组成,分别是声明循环变量、判断循环条件、更新循环变量。这三个表达式用分号分隔。可以使用临时变量将数组的长度缓存起来,避免重复获取数组长度,当数组较大时优化效果会比较明显。
const arr = [1,2,3,4,5]
for(let i = 0, len = arr.length; i < len; i++ ){
console.log(arr[i])
}
在执行的时候,会先判断执行条件,再执行。for循环可以用来遍历数组,字符串,类数组,DOM节点等。可以改变原数组。
2. while
while
循环中的结束条件可以是各种类型,但是最终都会转为布尔值,转换规则如下。
Boolean:true为真,false为假;
String:空字符串为假,所有非空字符串为真;
Number:0为假,非0数字为真;
null/Undefined/NaN:全为假;
Object:全为真。
let num = 1;
while (num < 10){
console.log(num);
num ++;
}
while
和for
一样,都是先判断,再执行。只要指定条件为 true,循环就可以一直执行代码。
3. do / while
该方法会先执行再判断,即使初始条件不成立,do/while
循环也至少会执行一次。
let num = 10;
do
{
console.log(num);
num--;
}
while(num >= 0);
console.log(num); //-1
不建议使用do / while来遍历数组。
4. for await of
for await...of
方法被称为异步迭代器,该方法是主要用来遍历异步对象。它是ES2018中引入的方法。
for await...of
语句会在异步或者同步可迭代对象上创建一个迭代循环,包括 String,Array,类数组,Map, Set和自定义的异步或者同步可迭代对象。这个语句只能在 async function
内使用:
function Gen (time) {
return new Promise((resolve,reject) => {
setTimeout(function () {
resolve(time)
},time)
})
}
async function test () {
let arr = [Gen(2000),Gen(100),Gen(3000)]
for await (let item of arr) {
console.log(Date.now(),item)
}
}
test()
输出结果: