成为出色的问题解决者(这就是开发人员)没有捷径可走。
精通是以练习为代价的。 由于算法和数据结构构成了每个软件的支柱,因此练习它们应该是您的首要任务。 作为最常用的存储值序列的数据结构,数组是必不可少的。
今天,我们将通过学习如何来磨练我们的技能:
*展平一个数组
* 删除数组中的重复项
*从对象数组中删除重复项
*对对象数组进行排序
*合并两个数组
*返回两个数组之间的差异
*检查数组是否包含重复元素
*返回两个数组的交集
*查找数组中最长的字符串
俗话说“熟能生巧”。 让我们搞定它
最简单的方法是使用内置的 .flat() 方法。flat() 方法采用可选的最大深度参数。
例如,给定以下数组:
const arr = [1, 2, [3, 4], [[5, 6], [7, 8]]];
展平的代码是:
const flattened = arr.flat(2); //最大深度
console.log(flattened); // [1, 2, 3, 4, 5, 6, 7, 8]
flat() 方法返回一个新数组,所有子数组以递归方式连接到指定深度。
您还可以创建自己的递归函数,迭代数组的元素并将它们添加到新数组中,一次一个。
这是一个示例,说明如何编写递归函数来展平数组:
function flatten(arr) {
let result = [];
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
result = result.concat(flatten(arr[i]));
} else {
result.push(arr[i]);
}
}
return result;
}
const arr = [1, [2, [3, [4]]], 5];
console.log(flatten(arr)); // [1, 2, 3, 4, 5]
您可以使用 .reduce() 方法和三元运算符使此函数更加简洁。
function flatten(arr) {
return arr.reduce((accumulator, currentItem) =>
Array.isArray(currentItem)
? accumulator.concat(flatten(currentItem))
: accumulator.concat(currentItem),
[]);
}
此函数具有线性时间复杂度(这意味着它对大型数组很有效)。它还具有恒定的空间复杂度(这意味着它不会随着数组大小的增加而占用更多内存)。
到目前为止,删除数组重复项的最简单和更简洁的方法是使用 Set 对象。
Set 对象仅存储唯一值,因此您可以从数组创建一个新集合,然后使用 Array.from() 方法将该集合转换回数组。
这是您可以使用 Set 对象执行此操作的一种方法:
const arr = [1, 2, 3, 1, 2, 3, 4, 5];
const unique = Array.from(new Set(arr));
console.log(unique); // [1, 2, 3, 4, 5]
您还可以使用我最喜爱的 .reduce()
const arr = [1, 2, 3, 1, 2, 3, 4, 5]
arr.reduce((accumulator, currentItem) => {
if (!accumulator.includes(currentItem))
accumulator.push(currentItem)
return accumulator
},[])
要对对象数组进行排序,您必须从对象中选择一个属性来对数组进行排序。
然后,您可以调用 .sort() 并将其传递给比较器函数。
这是比较器函数的工作原理:
以下是如何根据 name 属性的值对对象数组进行排序:
const arr = [
{name: 'Bob', age: 30},
{name: 'Alice', age: 25},
{name: 'Charlie', age: 35}
];
arr.sort((a, b) => {
if (a.name < b.name) { //你可以根据任意属性排序
return -1;
} else if (a.name > b.name) {
return 1;
} else {
return 0;
}
});
/*
[
{name: 'Alice', age: 25},
{name: 'Bob', age: 30},
{name: 'Charlie', age: 35}
] */
您还可以使用三元运算符来制作单行版本:
arr.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
注意:有时嵌套的三元组可能难以阅读。
请记住,sort() 方法会修改原始数组,因此如果您想保留原始数组,您应该先复制它。
要合并两个数组,您可以使用 concat() 方法。concat() 方法返回一个包含两个数组元素的新数组。
以下是如何使用 concat() 合并两个数组的示例:
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const merged = arr1.concat(arr2);
console.log(merged); // [1, 2, 3, 4, 5, 6]
更高级的或者更确切地说是 ES6 版本使用扩展运算符 (...)。扩展运算符将数组的元素扩展为单独的参数。
这就是它的样子
const merged = [...arr1, ...arr2];
console.log(merged); // [1, 2, 3, 4, 5, 6]
有两种方法:
如果你不介意修改源数组,您可以简单地使用 .push() 将另一个数组的元素添加到第一个数组的末尾。
arr1.push(...arr2);
console.log(arr1); // [1, 2, 3, 4, 5, 6]
有以下几种区别:
非对称
对称
以下是如何使用 filter() 方法查找两个数组之间的非对称差异:
const arr1 = [1, 2, 3, 4, 5];
const arr2 = [3, 4, 5, 6, 7];
const difference = arr1.filter(x => !arr2.includes(x));
console.log(difference); // [1, 2]
以下是为了获得对称差异:
const arr1 = [1, 2, 3, 4, 5];
const arr2 = [3, 4, 5, 6, 7];
const difference = arr1
.filter(x => !arr2.includes(x))
.concat(arr2.filter(x => !arr1.includes(x)));
console.log(difference); // [1, 2, 6, 7]
这种方法返回一个新数组并且不修改原始数组。
或者,您可以使用 Set 对象及其 .has() 而不是 .includes()
非对称差异:
const set = new Set(arr2);
const difference = arr1.filter(x => !set.has(x));
console.log(difference); // [1, 2]
对称差异:
const set = new Set(arr2);
const set1 = new Set(arr1)
const difference = arr1
.filter(x => !set.has(x))
.concat(arr2.filter(x => !set1.has(x)));
console.log(difference); // [1, 2, 6, 7]
最简单的方法是使用 Set 对象和 size 属性。
Set 对象仅存储唯一值,因此您可以从数组创建一个集合并将该集合的大小与原始数组的大小进行比较。
如果集合的大小小于数组的大小,则意味着数组包含重复元素。
以下是您的操作方式:
const arr = [1, 2, 3, 4, 5, 5];
const hasDuplicates = new Set(arr).size !== arr.length;
console.log(hasDuplicates); // true
您可以使用对象(也称为散列或字典)实现相同的目的
当您遍历数组时,您将当前值设置为键,将 true 设置为键的值。
如果您尝试访问一个键并且那里已经有一个值,则意味着您找到了一个重复项。
这是其中一种方法:
const hasDuplicates = (arr) => {
let hash = {}
for(let i = 0; i < arr.length; i++){
if(!hash[arr[i]]){
hash[arr[i]] = true
} else {
return true;
}
}
return false
}
console.log(hasDuplicates(arr)); // true
这两种方法都创建一个新对象(集合或哈希对象)并且不修改原始数组。它们还具有线性时间复杂度(它们对大型数组很有效)。
最常见的方法是使用 filter() 和 includes()。
代码如下:
const arr1 = [1, 2, 3, 4, 5];
const arr2 = [3, 4, 5, 6, 7];
const intersection = arr1.filter(x => arr2.includes(x));
console.log(intersection); // [3, 4, 5]
这种方法返回一个新数组并且不修改原始数组。
作为替代方案,您可以(再次)使用 Set 对象和 .has() 方法
const set = new Set(arr2);
const intersection = arr1.filter(x => set.has(x));
console.log(intersection); // [3, 4, 5]
你看到模式了吗? 每当使用普通对象解决问题时,您都可以使用 Set创建一个版本,反之亦然。
为此,您可以使用我们流行的 .reduce() 方法和一个函数来比较这些值。
比较器函数将当前字符串的长度与前一个最长字符串的长度进行比较,如果更长则返回当前字符串,否则返回前一个最长字符串。
你可以这样做:
const arr = ['short', 'medium', 'long', 'longest'];
const longest = arr.reduce((acc, x) => x.length > acc.length ? x : acc, '');
console.log(longest); // 'longest'
这种方法创建一个新变量(acc 或累加器)并且不修改原始数组。
时间复杂度是线性的(意味着它对大型数组是有效的)。
同样可以通过使用 sort() 方法和扩展运算符 (...) 来更简洁地找到数组中最长的字符串:
const longest = [...arr].sort((a, b) => b.length - a.length)[0];
console.log(longest); // 'longest'
在本文中我们介绍了:
*展平一个数组
* 删除数组中的重复项
*从对象数组中删除重复项
*对对象数组进行排序
*合并两个数组
*返回两个数组之间的差异
*检查数组是否包含重复元素
*返回两个数组的交集
*查找数组中最长的字符串
谢谢阅读!