Javascript数组研究06_手写实现_shift_slice_some_sort_splice

26 Array.shift()

26.1 基本介绍

shift() 方法从数组中删除第一个元素,并返回该元素的值。此方法会更改数组的长度。

array.shift()

输入参数:无。

输出:被移除的第一个元素。如果数组为空,则返回 undefined

注意事项

  • shift() 方法会修改原数组,是一个修改方法
  • 删除第一个元素后,后续元素的索引会依次减一。
26.2 手写实现
MyArray.prototype.shift = function() {if (this.length === 0) {return undefined;}let firstElement = this[0];for (let i = 1; i < this.length; i++) {// 整个数组索引1到length - 1 需要向前移动if (i in this) {// 空槽不可以以这种方式移动,会变成undefinedthis[i - 1] = this[i];} else {// 正确处理空槽德移动方式,delete对象德属性delete this[i - 1];}}// 删除最后一个元素,减少lengthdelete this[this.length - 1];this.length--;return firstElement;
};// 测试用例
let arr = new MyArray(1, 2, 3).concat([,,4]);
let shiftedElement = arr.shift();
console.log(shiftedElement); // 1
console.log(arr); // [2, 3]let emptyArr = new MyArray();
let shiftedFromEmpty = emptyArr.shift();
console.log(shiftedFromEmpty); // undefined
console.log(emptyArr); // []

难点总结

  • 处理稀疏数组:需要正确处理空槽,避免错误地复制undefined,需要使用delete this[i - 1]相当于移动了空槽。
  • 更新 length 属性:需要手动更新数组的 length 属性,删除delete数组德最后一个元素。

27 Array.slice()

27.1 基本介绍

slice() 方法返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象中。原始数组不会被修改。

array.slice()
array.slice(start)
array.slice(start, end)

输入参数

  • start(可选):开始提取的索引,默认为 0。负索引表示从末尾开始计算。
  • end(可选):结束提取的索引(不包括该索引),默认为数组长度。负索引表示从末尾开始计算。

输出:一个新的数组,包含从 startend(不包括 end)的元素。

注意事项

  • slice() 方法不会修改原数组,是一个复制方法
  • 对于稀疏数组,返回的新数组也会保留对应位置的空槽。
  • slice() 方法是通用方法,可用于类数组对象。
27.2 手写实现
MyArray.prototype.slice = function(start = 0, end = this.length) {let length = this.length >>> 0;// 处理负索引let relativeStart = start < 0 ? Math.max(length + start, 0) : Math.min(start, length);let relativeEnd = end < 0 ? Math.max(length + end, 0) : Math.min(end, length);let count = Math.max(relativeEnd - relativeStart, 0);let result = new MyArray();for (let i = 0; i < count; i++) {let index = relativeStart + i;// 只有在不是空槽的情况下才会赋值// 所以空槽其实就是不存在的对象属性if (index in this) {result[i] = this[index];}}// 不要忘记处理结果的数组长度result.length = count;return result;
};// 测试用例
let arr_1 = new MyArray(1, 2, 3, 4, 5);
let slicedArr = arr_1.slice(1, 3);
console.log(slicedArr); // [2, 3]let arr_2 = new MyArray().concat([1, , 3, , 5]);
let slicedArr2 = arr_2.slice(1, 4);
console.log(slicedArr2); // [empty, 3, empty]
console.log(slicedArr2.length); // 3

难点总结

  • 处理稀疏数组:返回的新数组需要保留空槽位置,空槽实际上就是不存在数组列表对象属性。
  • 计算长度:确保新数组的 length 属性设置正确。

28 Array.some()

28.1 基本介绍

some() 方法测试数组中是否至少有一个元素通过了由提供的函数实现的测试。如果在数组中找到一个元素使得提供的函数返回 true,则返回 true;否则返回 false。它不会修改数组。

array.some(callbackFn)
array.some(callbackFn, thisArg)

输入参数

  • callbackFn(element, index, array):用于测试每个元素的函数。
  • thisArg(可选):执行 callbackFn 时使用的 this 值。

输出:如果数组中至少有一个元素通过了测试,则返回 true;否则返回 false

注意事项

  • some() 方法不会修改原数组。
  • 一旦找到使 callbackFn 返回真值的元素,方法将立即返回 true,不会继续遍历。
  • 空数组会返回false
  • 对于稀疏数组,some() 会跳过空槽。
  • some() 方法是通用方法
28.2 手写实现
MyArray.prototype.some = function(callbackFn, thisArg) {if (typeof callbackFn !== 'function') {throw new TypeError(callbackFn + ' is not a function');}for (let i = 0; i < this.length; i++) {if (!(i in this)) continue; // 跳过空槽// 使用.call调用函数,绑定thisArgif (callbackFn.call(thisArg, this[i], i, this)) {return true;}}return false;
};// 测试用例
let arr_3 = new MyArray(1, 2, 3, 4);
let hasEven = arr_3.some(x => x % 2 === 0);
console.log(hasEven); // truelet arr_4 = new MyArray().concat([1, , 3]);
let hasUndefined = arr_4.some(x => x === undefined);
console.log(hasUndefined); // false

难点总结

  • 提前终止遍历:一旦 callbackFn 返回真值,some() 方法立即返回 true
  • 处理稀疏数组:跳过空槽,不调用 callbackFn
  • 正确绑定 thisArg:在调用 callbackFn 时需要正确绑定 thisArg

29 Array.sort()

29.1 基本介绍

sort() 方法用原地算法对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的 UTF-16 代码单元值序列时构建的。

array.sort()
array.sort(compareFunction)

输入参数

  • compareFunction(a, b)(可选):用于定义排序顺序的函数。返回值为负数表示 ab 之前,正数表示 ab 之后,零表示相等。

输出:排序后的数组。原数组已被修改。

注意事项

  • sort() 方法会修改原数组,是一个修改方法
  • 如果没有提供 compareFunction,元素会被转换为字符串,然后按字典顺序排序。
  • 对于undefined,会放在数组的结尾
  • 对于稀疏数组,sort() 会将空槽排在所有 undefined的后面
29.2 手写实现
MyArray.prototype.sort = function(compareFunction) {let length = this.length >>> 0;// 分离数组元素let elements = [];let undefinedElements = [];let holesCount = 0;for (let i = 0; i < length; i++) {if (i in this) {let value = this[i];if (value === undefined) {undefinedElements.push(value);} else {elements.push(value);}} else {holesCount++; // 统计空槽数量}}// 默认比较函数if (typeof compareFunction !== 'function') {compareFunction = function(a, b) {let strA = String(a);let strB = String(b);if (strA < strB) return -1;if (strA > strB) return 1;return 0;};}// 手写排序算法(快速排序)function quickSort(arr, left, right) {if (left >= right) return;let pivotIndex = partition(arr, left, right);quickSort(arr, left, pivotIndex - 1);quickSort(arr, pivotIndex + 1, right);}function partition(arr, left, right) {let pivot = arr[right];let i = left - 1;for (let j = left; j < right; j++) {if (compareFunction(arr[j], pivot) <= 0) {i++;[arr[i], arr[j]] = [arr[j], arr[i]];}}[arr[i + 1], arr[right]] = [arr[right], arr[i + 1]];return i + 1;}quickSort(elements, 0, elements.length - 1);// 清空原数组for (let i = 0; i < length; i++) {delete this[i];}// 重新赋值排序后的元素let index = 0;for (let i = 0; i < elements.length; i++) {this[index++] = elements[i];}// 添加 undefined 元素for (let i = 0; i < undefinedElements.length; i++) {this[index++] = undefined;}// 保留空槽(holes)this.length = index + holesCount;return this;
};// 测试用例 1:数字排序(未提供 compareFunction)
let arr_5 = new MyArray(3, undefined, 80, 9, undefined, 10);
arr_5[10] = 100; // 在索引 10 处创建一个元素,索引 6-9 为空槽
arr_5.sort();
console.log(arr_5); // [10, 100, 3, 80, 9, undefined, undefined, <4 empty items>]// 测试用例 2:字符串排序(未提供 compareFunction)
let arr_6 = new MyArray().concat(['banana', undefined, 'apple', , 'cherry']);
arr_6.sort();
console.log(arr_6); // ['apple', 'banana', 'cherry', undefined, <1 empty item>]// 测试用例 3:使用自定义比较函数(不区分大小写)
let arr_7 = new MyArray('Banana', 'apple', 'Cherry', undefined);
arr_7.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
console.log(arr_7); // ['apple', 'Banana', 'Cherry', undefined]// 测试用例 4:稀疏数组
let arr_8 = new MyArray();
arr_8[2] = 'c';
arr_8[5] = 'a';
arr_8[7] = undefined;
arr_8[9] = 'b';
arr_8.sort();
console.log(arr_8); // ['a', 'b', 'c', undefined, <6 empty items>]

难点总结

  • 实现排序算法:实现一个完整的排序算法(如快速排序)较为复杂。
  • 处理 compareFunction:需要正确处理用户提供的比较函数。
  • 处理稀疏数组及undefined:需要正确处理空槽和undefined,排序前将其转换为密集数组。
  • 原地修改:需要确保对原数组进行修改,而不是返回新数组。

30 Array.splice()

30.1 基本介绍

splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。

array.splice(start)
array.splice(start, deleteCount)
array.splice(start, deleteCount, item1, item2, ...)

输入参数

  • start:指定修改的开始位置(从 0 开始计数)。如果超出数组长度,则从数组末尾开始添加内容。如果为负值,表示从数组末尾开始计数。
  • deleteCount(可选):整数,表示要移除的数组元素的个数。
    • 如果 deleteCount 为 0,则不删除元素。
    • 如果 deleteCount 大于剩余元素的数量,则删除到数组末尾。
    • 如果未指定 deleteCount,则删除从 start 开始的所有元素。
  • item1, item2, ...(可选):要添加进数组的元素,从 start 位置开始插入。

输出:一个由被删除的元素组成的数组。如果没有删除元素,则返回空数组。

注意事项

  • splice() 方法会修改原数组,是一个修改方法
  • 如果仅添加元素,不删除,则 deleteCount 应为 0。
  • 如果仅删除元素,不添加,则不需要提供 item 参数。
  • 如果删除的部分是稀疏的,则splice()返回的数组也是稀疏的,对应的索引为空槽。
30.2 手写实现
MyArray.prototype.splice = function(start, deleteCount, ...items) {let length = this.length >>> 0;// 处理索引let actualStart = start < 0 ? Math.max(length + start, 0) : Math.min(start, length);let actualDeleteCount;if (arguments.length === 1) {// 只有start的情况下,会删除从start开始到结尾的元素actualDeleteCount = length - actualStart;} else if (arguments.length >= 2) {// 确保删除数目的合法性,最多只能到数组结尾actualDeleteCount = Math.min(Math.max(Number(deleteCount), 0), length - actualStart);} else {actualDeleteCount = 0;}let removedElements = new MyArray();// 取出要删除的元素-保留空槽for (let i = 0; i < actualDeleteCount; i++) {let fromIndex = actualStart + i;if (fromIndex in this) {removedElements[i] = this[fromIndex];}}removedElements.length = actualDeleteCount;// 添加和删除元素的数量差let itemCount = items.length;let shiftCount = itemCount - actualDeleteCount;if (shiftCount > 0) {// 需要后移元素for (let i = length - 1; i >= actualStart + actualDeleteCount; i--) {let fromIndex = i;let toIndex = i + shiftCount;if (fromIndex in this) {this[toIndex] = this[fromIndex];} else {delete this[toIndex];}}} else if (shiftCount < 0) {// 需要前移元素for (let i = actualStart + actualDeleteCount; i < length; i++) {let fromIndex = i;let toIndex = i + shiftCount;if (fromIndex in this) {this[toIndex] = this[fromIndex];} else {delete this[toIndex];}}// 删除多余的元素for (let i = length - 1; i >= length + shiftCount; i--) {delete this[i];}}// 插入新元素for (let i = 0; i < itemCount; i++) {this[actualStart + i] = items[i];}// 更新 lengththis.length = length + shiftCount;return removedElements;
};// 测试用例
let arr_9 = new MyArray(1, 2, 3, 4, 5);
let removed = arr_9.splice(2, 2, 'a', 'b');
console.log(arr_9); // [1, 2, 'a', 'b', 5]
console.log(removed); // [3, 4]let arr_10 = new MyArray(1, 2, 3);
let removed2 = arr_10.splice(1);
console.log(arr_10); // [1]
console.log(removed2); // [2, 3]let arr_11 = new MyArray(1, 2, 3);
let removed3 = arr_11.splice(-1, 0, 4, 5);
console.log(arr_11); // [1, 2, 4, 5, 3]
console.log(removed3); // []

难点总结

  • 计算索引及计算合法删除数量:需要正确处理 startdeleteCount,特别是负索引的情况。还要注意删除元素个数不能超过数组长度。
  • 元素移动与空槽处理:在添加或删除元素时,需要根据增加的元素和删除的元素正确移动数组中的其他元素,注意空槽的移动。
  • 更新 length 属性:操作完成后,需要更新数组的 length 属性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/439141.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微信小程序处理交易投诉管理,支持多小程序

大家好&#xff0c;我是小悟 1、问题背景 玩过微信小程序生态的&#xff0c;或许就有这种感受&#xff0c;如果收到投诉单&#xff0c;不会及时通知到手机端&#xff0c;而是每天早上10:00向小程序的管理员及运营者推送通知。通知内容为截至前一天24时该小程序账号内待处理的交…

哪款百元头戴式耳机性价比高?四款大火爆全网的机型盘点推荐!

在繁忙的生活节奏中&#xff0c;寻找一片属于自己的宁静空间&#xff0c;成为了许多人的内心渴望。头戴式降噪耳机&#xff0c;正是那把打开音乐世界的钥匙。它不仅能够隔绝外界的喧嚣&#xff0c;还能将您带入一个纯净无瑕的音乐世界。无论是沉浸在古典乐的悠扬旋律中&#xf…

66 使用注意力机制的seq2seq_by《李沐:动手学深度学习v2》pytorch版

系列文章目录 文章目录 系列文章目录动机加入注意力总结代码定义注意力解码器训练小结练习 我们来真的看一下实际应用中&#xff0c;key&#xff0c;value&#xff0c;query是什么东西&#xff0c;但是取决于应用场景不同&#xff0c;这三个东西会产生变化。先将放在seq2seq这个…

平面电磁波的电场能量磁场能量密度相等,能量密度的体积分等于能量,注意电场能量公式也没有复数形式(和坡印廷类似)

1、电场能量密度和磁场能量密度相等(实数场算的) 下面是电场能量密度和磁场能量密度的公式&#xff0c;注意这可不是坡印廷定理。且电场能量密度没有复数表达式&#xff0c;即不是把E和D换成复数形式就行的。注意&#xff0c;一个矢量可以转化为复数形式&#xff0c;两个矢量做…

深入计算机语言之C++:C到C++的过度

&#x1f511;&#x1f511;博客主页&#xff1a;阿客不是客 &#x1f353;&#x1f353;系列专栏&#xff1a;从C语言到C语言的渐深学习 欢迎来到泊舟小课堂 &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 一、什么是C C&#xff08;c plus plus&#xff…

使用NumPy进行线性代数的快速指南

介绍 NumPy 是 Python 中用于数值计算的基础包。它提供了处理数组和矩阵的高效操作&#xff0c;这对于数据分析和科学计算至关重要。在本指南中&#xff0c;我们将探讨 NumPy 中可用的一些基本线性代数操作&#xff0c;展示如何通过运算符重载和内置函数执行这些操作。 元素级…

Linux 文件 IO 管理(第四讲:软硬链接和动静态库)

Linux 文件 IO 管理&#xff08;第四讲&#xff1a;软硬链接和动静态库&#xff09; 软硬链接操作与现象软链接硬链接 解释软链接硬链接作用 动静态库初识静态库怎么做库&#xff08;开发角度&#xff09;怎么用库&#xff08;使用角度&#xff09;安装当前目录直接使用 动态库…

打卡第一天 B2005 字符三角形

今天是我打卡第一天&#xff0c;就做个水题吧(#^.^#) 题目描述 给定一个字符&#xff0c;用它构造一个底边长 55 个字符&#xff0c;高 33 个字符的等腰字符三角形。 输入格式 输入只有一行&#xff0c;包含一个字符。 输出格式 该字符构成的等腰三角形&#xff0c;底边长…

全新一区PID搜索算法+TCN-LSTM+注意力机制!PSA-TCN-LSTM-Attention多变量时间序列预测(Matlab)

全新一区PID搜索算法TCN-LSTM注意力机制&#xff01;PSA-TCN-LSTM-Attention多变量时间序列预测&#xff08;Matlab&#xff09; 目录 全新一区PID搜索算法TCN-LSTM注意力机制&#xff01;PSA-TCN-LSTM-Attention多变量时间序列预测&#xff08;Matlab&#xff09;效果一览基本…

今日凌晨,ChatGPT重磅更新!—— 我心目中的终极AGI界面

今日凌晨&#xff0c;ChatGPT重磅更新&#xff01;—— 我心目中的终极AGI界面 我心目中的终极 AGI 界面是一张空白画布&#xff08;canvas&#xff09;。 今日凌晨&#xff0c;OpenAI 发布 canvas&#xff0c;一个与 ChatGPT 合作写作和编程的新界面&#xff01; canvas&…

MySQL 启动失败 (code=exited, status=1/FAILURE) 异常解决方案

目录 前言1. 问题描述2. 查看错误日志文件2.1 确认日志文件路径2.2 查看日志文件内容 3. 定位问题3.1 问题分析 4. 解决问题4.1 注释掉错误配置4.2 重启 MySQL 服务 5. 总结结语 前言 在日常运维和开发过程中&#xff0c;MySQL数据库的稳定运行至关重要。然而&#xff0c;MySQ…

Leetcode—148. 排序链表【中等】

2024每日刷题&#xff08;171&#xff09; Leetcode—148. 排序链表 C实现代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr…

森林火灾检测数据集 7400张 森林火灾 带标注 voc yolo

森林火灾检测数据集 7400张 森林火灾 带标注 voc yolo 森林火灾检测数据集 名称 森林火灾检测数据集 (Forest Fire Detection Dataset) 规模 图像数量&#xff1a;共7780张图像。类别&#xff1a;仅包含一种类别——火源。 数据划分 训练集 (Train)&#xff1a;通常占总数据…

SpringBoot整合JPA详解

SpringBoot版本是2.0以上(2.6.13) JDK是1.8 一、依赖 <dependencies><!-- jdbc --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jdbc</artifactId></dependency><!--…

Oracle SQL语句没有过滤条件,究竟是否会走索引??

答案是&#xff1a;可能走索引也可能不走索引&#xff0c;具体要看列的值可不可为null&#xff0c;Oracle不会为所有列的nullable属性都为Y的sql语句走索引。 例子&#xff1a; create table t as select * from dba_objects; CREATE INDEX ix_t_name ON t(object_id, objec…

9.30学习记录(补)

手撕线程池: 1.进程:进程就是运行中的程序 2.线程的最大数量取决于CPU的核数 3.创建线程 thread t1; 在使用多线程时&#xff0c;由于线程是由上至下走的&#xff0c;所以主程序要等待线程全部执行完才能结束否则就会发生报错。通过thread.join()来实现 但是如果在一个比…

SpringBoot助力校园资料分享:快速上手指南

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多学生、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常适…

多模态—文字生成图片

DALL-E是一个用于文字生成图片的模型&#xff0c;这也是一个很好思路的模型。该模型的训练分为两个阶段&#xff1a; 第一阶段&#xff1a;图片经过编码器编码为图片向量&#xff0c;当然我们应该注意这个过程存在无损压缩&#xff08;图片假设200*200&#xff0c;如果用one-h…

MATLAB|基于多主体主从博弈的区域综合能源系统低碳经济优化调度

目录 主要内容 程序亮点&#xff1a; 模型研究 一、综合能源模型 二、主从博弈框架 部分代码 结果一览 下载链接 主要内容 程序参考文献《基于多主体主从博弈的区域综合能源系统低碳经济优化调度》&#xff0c;采用了区域综合能源系统多主体博弈协同优化方…