成为算法专家必须了解的 Map、Filter、Reduce 和其他数组迭代器
在本文中,我们将仔细研究一些数组迭代器,例如map、filter、reduce或其他使用回调的方法,它们使数组更加灵活,并帮助您解决 JavaScript 中的问题和算法。
学习这些高阶函数是编写简洁函数式代码的重要一步,并开启了通往函数式和响应式编程等强大技术的大门。
1) 使用forEach()循环数组;for 循环
的一个绝佳替代方案无疑是forEach方法。它循环遍历数组并使用每个值作为参数调用回调函数。回调函数接受 3 个不同的参数:数组中的值、当前索引以及调用回调函数的数组。此外,还有第四个参数,用于在执行回调时用作this(如果未提供,则为undefined)。 注意:forEach()不会改变调用它的数组。
const cities = ['ROME', 'PARIS', 'LONDON', 'LOS ANGELES', 'VIENNA'];
cities.forEach((value, index, array) => {
console.log(`${index + 1} ${value}`); //output: 1 ROME, 2 PARIS, 3 LONDON, 4 LOS ANGELES, 5 VIENNA
});
//we can use it to invert the "cities" array...even though with reverse() would be better 😉
const invertedCities = [];
cities.forEach((value, index, array) => invertedCities.unshift(value));
console.log(invertedCities); //output: ["VIENNA", "LOS ANGELES", "LONDON", "PARIS", "ROME"]
2) 使用map()创建一个新数组,其中包含对原始数组的每个元素调用的函数的结果;与forEach()
方法 非常相似。它遍历一个数组,并将回调函数作为参数,该函数在原始数组中的每个元素上调用。不同之处在于,它返回一个新数组,该数组中的每个值都替换为回调函数的返回值。
//Let's create a new array with all our numbers squared
const numbers = [1, 2, 3, 4, 5];
const squaredNumbers = numbers.map(number => number * number);
console.log(squaredNumbers); //output: [1, 4, 9, 16, 25]
//We all know which is the most beautiful city in the World... 😉
const cities = ['ROME', 'PARIS', 'LONDON', 'LOS ANGELES', 'VIENNA'];
const bestCity = cities.map(city => (city === 'ROME' ? city : 'ROME'));
console.log(bestCity); //output: ["ROME", "ROME", "ROME", "ROME", "ROME"]
//Let's create an array of HTML tag
const html = cities.map(city => `<li>${city}</li>`);
console.log(html); //output: ["<li>ROME</li>", "<li>PARIS</li>", "<li>LONDON</li>", "<li>LOS ANGELES</li>", "<li>VIENNA</li>"]
//Transform an array of strings in an array of objects
const metalBands = ['IRON MAIDEN', 'SLAYER', 'JUDAS PRIEST'];
const collection = metalBands.map((band, index) => {
let obj = {}; //create an empty object at any call of the loop
obj.id = index; //create a key called "id" and set it equal to our index parameter
obj.band = band; //create a key called "band" and set it equal to our band parameter
return obj; //return an object at any call with key/value pairs like this: {id: 'index', band: 'band-name'}
});
console.log(collection); //output: [{id: 0, band: "IRON MAIDEN"},{id: 1, band: "SLAYER"}, {id: 2, band: "JUDAS PRIEST"}]
3) 使用filter()过滤数组的值;
它返回一个新数组,该数组仅包含原始数组中传递给回调时返回 true 的项目。
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
//Return an array of even values from numbers
const evens = numbers.filter(num => num % 2 === 0);
console.log(evens); //output: [2, 4, 6, 8, 10]
//Return an array of odd values from numbers
const odds = numbers.filter(num => num % 2 !== 0);
console.log(odds); //output: [1, 3, 5, 7, 9]
//All the roads lead to Rome 🚋 ...
const cities = ['ROME', 'PARIS', 'LONDON', 'LOS ANGELES', 'VIENNA'];
const rome = cities.filter(city => city == 'ROME');
console.log(rome); //output: ["ROME"]
//You can chain together this methods 🚀🚀🚀
//Example: let's square all even numbers
const squaredEvens = numbers.filter(num => num % 2 === 0).map(num => num * num);
console.log(squaredEvens); //output: [4, 16, 36, 64, 100];
4) 使用reduce()将每个结果累加合并,返回单个值;
真正的魔法就在这里!reduce()是函数式编程的“基石”,如果你掌握了它,你就走上了成为 JS 巫师的正确道路 🤘😉🤘
它是另一种遍历数组中每个项目的方法,但这次它将每个结果累加合并,返回单个值。
回调函数用于描述如何将数组中的每个值与运行总数合并。这通常用于计算存储在数组中的数据。Reducer
函数接受四个参数:累加器、当前值、当前索引和源数组。它还接受一个初始值,用作回调函数首次调用的第一个参数。
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
//Let's start with a basic example
//Sum all the numbers in an array of integers
const sum = numbers.reduce((accumulator, currentValue, currentIndex, array) => {
//Look we set the Initial Value to 0, because it is a sum so the count starts at 0
//So our Accumulator is 0 at first call and we sum it with the Current Value that is 1 at first call...
//the new Accumulator will be 0 + 1 = 1 ...at any call the Current Value will be added to it
//till the end of the array
return accumulator + currentValue;
}, 0);
console.log(sum); // output: 55
//Same example setting the Initial Value to 1 instead of 0 will return ... 56
const anotherSum = numbers.reduce((accumulator, currentValue, currentIndex, array) => {
return accumulator + currentValue;
}, 1);
console.log(anotherSum); // output: 56
//Sum from an array of objects
const integers = [{ x: 1 }, { x: 2 }, { x: 3 }];
const anotherSumAgain = integers.reduce((acc, val, idx, array) => {
return acc + val.x;
}, 0);
console.log(anotherSumAgain); // output: 6
//Count vowels in a string (even though it's easier with regex 😉)
const maryPoppins = 'supercalifragilisticexpialidocious';
const onlyVowels = maryPoppins.replace(/[^aeiou]/gi, ''); //'ueaiaiiieiaioiou'
const arrOfVowels = [...onlyVowels]; //["u", "e", "a", "i", "a", "i", "i", "i", "e", "i", "a", "i", "o", "i", "o", "u"]
const countVowels = arrOfVowels.reduce((acc, val) => {
acc.hasOwnProperty(val) ? (acc[val] += 1) : (acc[val] = 0);
return acc;
}, {});
console.log(countVowels); // output: {u: 1, e: 1, a: 2, i: 6, o: 1}
//Flatten an array of arrays
//Hey! I know ES2019 gave us flat and flatMap methods, but we MUST learn reduce() now 😉
const someData = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
const flatten = someData.reduce((acc, val) => {
//set the initial value to an empty array
return acc.concat(val);
}, []);
console.log(flatten); // output: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
//Sum all countries population except China
const population = [
{
country: 'China',
pop: 1409517397
},
{
country: 'India',
pop: 1339180127
},
{
country: 'USA',
pop: 324459463
},
{
country: 'Indonesia',
pop: 263991379
}
];
const sumPopulationButNotChina = population.reduce((acc, val) => {
// we use the Ternary Operator as a "filter"
//if val.country is not equal to "China" we add the value to the accumulator
//if it is equal to "China" we add nothing and simply return the accumulator
return val.country !== 'China' ? acc + val.pop : acc;
}, 0);
console.log(sumPopulationButNotChina); // output: 1927630969
与reduce()类似的是reduceRight。它对一个累加器和数组中的每个值应用一个函数,但顺序是从右到左。这里就不赘述了,因为这只会重复reduce()中已经讲过的内容。
5) 使用every()检查所有数组项是否通过测试;
用于测试的回调函数接受 3 个参数:当前值、索引和数组。返回值为布尔值。如果回调函数对数组中任何元素返回真值,则返回 True。否则返回 false。
//Check if all values are more than zero
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const moreThanZero = numbers.every((val, index, array) => val > 0);
console.log(moreThanZero); //true
const numbersAgain = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const moreThanZeroAgain = numbersAgain.every((val, index, array) => val > 0);
console.log(moreThanZeroAgain); //false
//Check if there are more than 1000000 people in all the countries
const population = [
{
country: 'China',
pop: 1409517397
},
{
country: 'India',
pop: 1339180127
},
{
country: 'USA',
pop: 324459463
},
{
country: 'Indonesia',
pop: 263991379
}
];
const check = population.every(val => val.pop > 1000000);
console.log(check); //true
6) 使用some()检查数组中的某些项是否通过测试;
用于测试的回调函数接受 3 个参数:当前值、索引和数组。返回值为布尔值。如果回调函数为数组中至少一个元素返回真值,则返回 True。否则返回 false。
//Check if a value is more than zero in the array
const numbers = [-1, -2, 0, 10];
const moreThanZero = numbers.some((val, index, array) => val > 0);
console.log(moreThanZero); //true
const numbersAgain = [0, -1, -2];
const moreThanZeroAgain = numbersAgain.some((val, index, array) => val > 0);
console.log(moreThanZeroAgain); //false
//Check if there is at least a country with less than 1000000 people
const population = [
{
country: 'China',
pop: 1409517397
},
{
country: 'India',
pop: 1339180127
},
{
country: 'USA',
pop: 324459463
},
{
country: 'Indonesia',
pop: 263991379
}
];
const check = population.some(val => val.pop < 1000000);
console.log(check); //false
7) 使用find()查找第一个通过测试的数组项;
用于测试的回调函数接受 3 个参数:当前值、索引和数组。如果至少有一个项通过了测试,则返回该项本身。否则返回undefined。
//Check if there is a value more than 7
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const moreThanSeven = numbers.find((val, index, array) => val > 7);
console.log(moreThanSeven); //8
//Check if there is a value more than 42
const moreThanFortyTwo = numbers.find((val, index, array) => val > 42);
console.log(moreThanFortyTwo); //undefined
//Check if there is a country with more than 100000000 people
const population = [
{
country: 'China',
pop: 1409517397
},
{
country: 'India',
pop: 1339180127
},
{
country: 'USA',
pop: 324459463
},
{
country: 'Indonesia',
pop: 263991379
}
];
const check = population.find(val => val.pop > 100000000);
console.log(check); //{ country: 'China', pop: 1409517397 }
这并不是一份详尽的 JavaScript 数组迭代器清单,而是一份我认为在解决问题和算法方面最重要的迭代器清单。
为了提高 JavaScript 水平和解决问题的能力,我建议多尝试所有这些方法,并订阅FreeCodeCamp或Codewars,在那里你可以找到很多可用的算法,并巩固你的 JavaScript 知识。
在Codewars上,你可以找到 7 级或 6 级关于“数组”的算法,并用它们进行训练。这会很有趣也很实用!
如果您对这类文章感兴趣,请看一下这些:
成为算法向导必须知道的 Javascript 字符串方法;
成为算法向导必须知道的 Javascript 数组方法
我会根据大家的反馈和评论,更新这篇文章,提供一些关于数组的新信息和算法。
欢迎关注我的Twitter。
代码长存,繁荣昌盛
文章来源:https://dev.to/uptheirons78/map-filter-reduce-and-others-arrays-iterators-you-must-know-to-become-an-algorithms-wizard-4209