首页 文章 精选 留言 我的

精选列表

搜索[Excel导题],共7152篇文章
优秀的个人博客,低调大师

前端百题——竟然有五种方式实现flat方法

1 背景 不知道老铁们有没有遇到过一道面试题:如何将一个多维数组展开成一个一维数组?当时我遇到的时候还不了解flat这个神奇的方法,用了最传统的解决方法进行解决。 const flatten = arr => arr.toString().split(',').map(item => +item); const arr = [1, 2, [3, 4, [5, 6]]]; console.log(flatten(arr)); // [ 1, 2, 3, 4, 5, 6 ] 复制代码 上述方法是不是很神奇,会将多层级的数组展开成为一个层级,但是该方式其实存在很大问题的,下面让我们一起看看这些问题。 不管多少层级都会展开为一个层级; 处理后的结果其实都是字符串,需要后续再转换为原来的类型。 正是基于这个契机,发现了ES6新增了flat函数,这个函数天生就是为数据扁平化处理而生的。 2 flat基础 flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。 flat方法的用法如下所示: const newArray = arr.flat([depth]) 复制代码 小试牛刀 const arr = [1, 2, [3, 4, [5, 6]]]; console.log(arr.flat(1)); // [ 1, 2, 3, 4, [ 5, 6 ] ] console.log(arr.flat(2)); // [ 1, 2, 3, 4, 5, 6 ] 复制代码 3 实现 flat这么香,那么我们是否可以自己实现一个呢?实现该方法的方式有很多,下面就让我们一起看看这五种方式。(注:这五种方式试MDN上给出的替代方案) 3.1 使用reduce和concat 该方式实现起来虽然很简单,但是存在一个很大的缺陷:只能展开一层,对于多层的情况将无能为力。其思想总结起来为以下两个步骤: 利用reduce函数去依次处理每个数组中的元素; 利用concat将当前的数组元素(值或子数组)添加到结果数组中。 // 使用reduce和concat Array.prototype.flat1 = function () { return this.reduce((acc, val) => acc.concat(val), []); } 复制代码 3.2 使用reduce + concat + isArray + recursivity 该方式已经具备展开多层的能力了,其实现思想可总结为以下几点: 利用reduce函数去依次处理每个数组中的元素; 利用concat将当前元素添加到结果数组中; 利用isArray判断当前数组中的元素是不是一个数组; 利用递归思想展开多层级的数组。 // 使用reduce + concat + isArray +recursivity Array.prototype.flat2 = function (deep = 1) { const flatDeep = (arr, deep = 1) => { return deep > 0 ? arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? flatDeep(val, deep - 1) : val), []) : arr.slice(); } return flatDeep(this, deep); } 复制代码 3.3 使用forEach + concat + isArray +recursivity 该方式与上述方式很类似,能够设定层级展开,只是遍历数组由reduce转换为forEach。 // 使用forEach + concat + isArray +recursivity // forEach 遍历数组会自动跳过空元素 Array.prototype.flat3 = function (deep = 1) { const result = []; (function flat(arr, deep) { arr.forEach((item) => { if (Array.isArray(item) && deep > 0) { flat(item, deep - 1); } else { result.push(item); } }) })(this, deep); return result; } 复制代码 3.4 使用for of + concat + isArray +recursivity 该方式与上述方式很类似,能够设定层级展开,只是遍历数组利用了for of方法 // 使用for of + concat + isArray +recursivity // for of 遍历数组会自动跳过空元素 Array.prototype.flat4 = function (deep = 1) { const result = []; (function flat(arr, deep) { for(let item of arr) { if (Array.isArray(item) && deep > 0) { flat(item, deep - 1); } else { // 去除空元素,因为void 表达式返回的都是undefined,不适用undefined是因为undefined在局部变量会被重写 item !== void 0 && result.push(item); } } })(this, deep); return result; } 复制代码 3.5 使用堆栈stack 该方式主要利用堆栈的思想,将一个多层数组全部展开为一层。其思想可总结为以下几个步骤: 将要处理的数组放到一个栈中处理; 从栈顶取出元素,判断该元素类型,若为数组,则将该数组展开再放回栈顶;若为普通元素则将其放到结果中; 循环遍历,至到栈为空。 // 使用堆栈stack Array.prototype.flat5 = function() { const stack = [...this]; const result = []; while (stack.length > 0) { const next = stack.pop(); if (Array.isArray(next)) { stack.push(...next); } else { result.push(next); } } // 反转恢复原来顺序 return result.reverse(); } 复制代码 1.如果觉得这篇文章还不错,来个分享、点赞吧,让更多的人也看到 如果你觉得这篇文章对你有点用的话,麻烦请给我们的开源项目点点star: http://github.crmeb.net/u/defu 不胜感激 ! 来自 “开源世界 ” ,链接: https://ym.baisou.ltd/post/737.html ,如需转载,请注明出处,否则将追究法律责任。 ​​​​​​

优秀的个人博客,低调大师

前端进阶算法4:链表原来如此简单(+leetcode刷题)

引言 链表相对于数组来说,要复杂的多,首先,链表不需要连续的内存空间,它是由一组零散的内存块透过指针连接而成,所以,每一个块中必须包含当前节点内容以及后继指针。最常见的链表类型有单链表、双链表以及循环链表。 学习链表最重要的是 多画图多练习 ,没有捷径可循,在遇到链表问题时,瓶子君总结了一下,可以按照以下五步骤: 确定解题的数据结构:单链表、双链表或循环链表等 确定解题思路:如何解决问题 画图实现:画图可以帮助我们发现思维中的漏洞(一些思路不周的情况) 确定边界条件:思考解题中是否有边界问题以及如何解决 代码实现:解题完成 本文会给常用链表(单链表、双链表以及循环链表)的基本操作已经代码实现,并给出实现思路,这些都是链表解题的基石,请务必掌握! 最后附赠一道 leetcode 题目! 下面开始本节的学习吧!!! 一、单链表 img 单链表结构: function List () { // 节点 let Node = function (element) { this.element = element this.next = null } // 初始头节点为 null let head = null // 链表长度 let length = 0 // 操作 this.getList = function() {return head} this.search = function(list, element) {} this.append = function(element) {} this.insert = function(position, element) {} this.remove = function(element){} this.isEmpty = function(){} this.size = function(){} } 1. 追加节点: 确定解题的数据结构:单链表 确定解题思路: 初始化一个节点(待追加节点),遍历到链尾,在尾节点后插入该节点 画图实现: 确定边界条件: 当链表为 null ,直接将 head 指向待插入节点,不需要遍历 代码实现: function append (element) { let node = new Node(element), p = head if (!head){ head = node } else { while (p.next) { p = p.next } p.next = node } length += 1 } // 测试 let list = new List() for(let i = 0; i < 5; i+=1) { list.append(i) } 解题完成 2. 查找: 确定解题的数据结构:单链表 确定解题思路: 遍历单链表,判断节点值是否等于待查找值,相等则返回 true ,否则继续遍历下一个节点,直到遍历完整个链表还未找到,则返回 false 画图实现: 很简单,读者可以尝试画一下 确定边界条件: 当链表为 null ,可直接返回 false 代码实现: // 判断链表中是否存在某节点 function search(element) { let p = head if (!p) return false while(p) { if (p.element === element) return true p = p.next } return false } // 测试 list.search(4) // true list.search(11) // false 解题完成 3. 在 position 位置插入: 确定解题的数据结构:单链表 确定解题思路: 初始化一个节点(待插入节点 node ),遍历到 position 前一个位置节点,在该节点后插入 node 画图实现:img 确定边界条件: 当 position 为 0 时,直接将插入节点 node.next 指向 head , head 指向 node 即可,不需要遍历 当待插入位置 position < 0 或超出链表长度 position > length ,都是有问题的,不可插入,此时直接返回 null ,插入失败 代码实现: // 插入 position 的后继节点 function insert (position, element) { // 创建插入节点 let node = new createNode(element) if (position >= 0 && position <= length) { let prev = head, curr = head, index = 0 if(position === 0) { node.next = head head = node } else { while(index < position) { prev = curr curr = curr.next index ++ } prev.next = node node.next = curr } length += 1 } else { return null } } // 测试 list.insert(10) 解题完成 4. 删除: 确定解题的数据结构:单链表 确定解题思路: 遍历单链表,找到待删除节点,删除 画图实现:img 确定边界条件: 当链表为 null ,直接返回 代码实现: // 删除值为 element 节点 function remove (element) { let p = head, prev = head if(!head) return while(p) { if(p.element === element) { p = p.next prev.next = p } else { prev = p p = p.next } } } 解题完成 5. 复杂度分析: 查找:从头节点开始查找,时间复杂度为 O(n) 插入或删除:在某一节点后插入或删除一个节点(后继节点)的时间复杂度为 O(1) 链表五步骤是不是很好用,下面看一下双链表 二、双链表 顾名思义,单链表只有一个方向,从头节点到尾节点,那么双链表就有两个方向,从尾节点到头节点: function DoublyLinkedList() { let Node = function(element) { this.element = element // 前驱指针 this.prev = null // 后继指针 this.next = null } // 初始头节点为 null let head = null // 新增尾节点 let tail = null // 链表长度 let length = 0 // 操作 this.search = function(element) {} this.insert = function(position, element) {} this.removeAt = function(position){} this.isEmpty = function(){ return length === 0 } this.size = function(){ return length } } 1. 在 position 位置插入节点: 确定解题的数据结构: 双链表 确定解题思路: 初始化一个节点(待插入节点 node ),遍历链表到 position 前一个位置节点,在该节点位置后插入 node 画图实现: 确定边界条件: 当待插入位置 position < 0 或超出链表长度 position > length ,都是有问题的,不可插入,此时直接返回 null ,插入失败 代码实现: // 插入 position 的后继节点 function insert (position, element) { // 创建插入节点 let node = new Node(element) if (position >= 0 && position < length) { let prev = head, curr = head, index = 0 if(position === 0) { // 在第一个位置添加 if(!head) { // 注意这里与单链表不同 head = node tail = node } else { // 双向 node.next = head head.prev = node // head 指向新的头节点 head = node } } else if(position === length) { // 插入到尾节点 curr = tial curr.next = node node.prev = curr // tail 指向新的尾节点 tail = node } else { while(index < position) { prev = curr curr = curr.next index ++ } // 插入到 prev 后,curr 前 prev.next = node node.next = curr curr.prev = node node.prev = prev } length += 1 return true } else { return false } } // 测试 list.insert(10) 解题完成 2. 删除: 确定解题的数据结构: 双链表 确定解题思路: 遍历双链表,找到待删除节点,删除 画图实现: 确定边界条件: 当链表为 null ,直接返回 代码实现: // 删除 position 位置的节点 function removeAt (position) { if (position >= 0 && position < length && length > 0) { let prev = head, curr = head, index = 0 if(position === 0) { // 移除头节点 if(length === 1) { // 仅有一个节点 head = null tail = null } else { head = head.next head.prev = null } } else if(position === length-1) { // 移除尾节点 curr = tial tail = curr.prev tail.next = null } else { while(index < position) { prev = curr curr = curr.next index ++ } // 移除curr prev.next = curr.next curr.next.prev = prev } length -= 1 return curr.element } else { return null } } 解题完成 3. 查找: 双链表的查找和单链表类似,都是遍历链表,找到返回 true,找不到返回 false 。 4. 复杂度分析: 查找:查找前驱节点或后继节点时间复杂度为 O(1),其它节点仍为 O(n) 插入或删除:插入或删除前驱节点或后继节点的时间复杂度都为 O(1) > 三、循环单链表 循环单链表是一种特殊的单链表,它和单链表的唯一区别是:单链表的尾节点指向的是 NULL,而循环单链表的尾节点指向的是头节点,这就形成了一个首尾相连的环:img 既然有循环单链表,当然也有循环双链表,循环双链表和双链表不同的是: 循环双链表的 tail.next( tail 的后继指针) 为 null ,循环双链表的 tail.next 为 head 循环双链表的 head.prev( head 的前驱指针) 为 null ,循环双链表的 head.prev 为 tail 这里以循环单列表为例 function CircularLinkedList() { let Node = function(element) { this.element = element // 后继指针 this.next = null } // 初始头节点为 null let head = null // 链表长度 let length = 0 // 操作 this.search = function(element) {} this.insert = function(positon, element) {} this.removeAt = function(position){} this.isEmpty = function(){ return length === 0 } this.size = function(){ return length } } 1. 在 positon 后插入: 确定解题的数据结构: 循环单链表 确定解题思路: 初始化一个节点(待插入节点 node ),遍历到 position 前一个位置节点,在该节点后插入 node 画图实现: 确定边界条件: 当 position 为 0 时,需要遍历到尾节点,然后在尾节点后插入节点 , 并将 head 指向 当待插入位置 position < 0 或超出链表长度 position > length ,都是有问题的,不可插入,此时直接返回 null ,插入失败 代码实现: // 插入 position 的后继节点 function insert (position, element) { // 创建插入节点 let node = new createNode(element) if (position >= 0 && position <= length) { let prev = head, curr = head, index = 0 if(position === 0) { // 与单链表插入不同的 while(index < length) { prev = curr curr = curr.next index ++ } prev.next = node node.next = curr head = node } else { while(index < position) { prev = curr curr = curr.next index ++ } prev.next = node node.next = curr } length += 1 } else { return null } } // 测试 list.insert(10) 解题完成 2. 查找: 和单链表类似,唯一不同的是:循环单链表的循环结束条件为 p !== head // 判断链表中是否存在某节点 function search(element) { let p = head if (!p) return false // 和单链表的不同所在 while(p !== head) { if (p.element === element) return true p = p.next } return false } // 测试 list.search(4) // true list.search(11) // false 解题完成 3. 删除: 和单链表类似,唯一不同的是:循环单链表的循环结束条件为 p !== head // 删除值为 element 节点 function remove (element) { let p = head, prev = head if(!head) return while(p !== head) { if(p.element === element) { p = p.next prev.next = p } else { prev = p p = p.next } } } 解题完成 4. 复杂度分析 查找:循环链表从任一节点开始查找目标节点,时间复杂度为 O(n) 插入或删除:它和单链表一样,后继节点插入及删除的时间复杂度为 O(1) > 四、leetcode21:合并两个有序链表 将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例: 输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4 欢迎将答案提交到 https://github.com/sisterAn/JavaScript-Algorithms/issues/11,让更多人看到,瓶子君也会在明日放上自己的解答。

优秀的个人博客,低调大师

CCAH-CCA-500-4题:Where are Hadoop task log files stored?

4.Where are Hadoop task log files stored? For each YARN job, the Hadoop framework generates task log file. Where are Hadoop task log files stored? A. Cached by the NodeManager managing the job containers, then written to a log directory on the NameNode B. Cached in the YARN container running the task, then copied into HDFS on job completion C. In HDFS, in the directory of the user who generates the job D. On the local disk of the slave mode running the task 问题: 对于每个yarn job,hadoop框架产生的task日志文件存储在哪个位置上? 解析: 1.对于学习hadoop有段时间的和亲手搭建过,就会知道log文件一般 肯定是存储在 local disk(本地磁盘)上,而不是存储在hdfs文件系统中。 2.一般输出位置由yarn.nodemanager.log-dirs参数设置(Default Pathis ${yarn.log.dir}/userlogs) <property> <name>yarn.nodemanager.log-dirs</name> <value>/home/root/workspace-yarn/nm/log</value> </property>. 如果不配置将使得NodeManager进程处于Unhealthy状态,无法提供服务,现象是提交作业时,作业一直处于pending状态无法往下执行,所以必须配置。

优秀的个人博客,低调大师

CCAH-CCA-500-2题:what is the maximum number of NameNode daemons.....

2.Assuming you’re not running HDFS Federation, what is the maximum number of NameNode daemons you should run on your cluster in order to avoid a “split-brain” scenario with your NameNode when running HDFS High Availability (HA) using Quorum-based storage? A. Two active NameNodes and two Standby NameNodes B. One active NameNode and one Standby NameNode C. Two active NameNodes and on Standby NameNode D. Unlimited. HDFS High Availability (HA) is designed to overcome limitations on the number of NameNodes you can deploy 问题: 当集群没有配置HDFS Federation时,而配置HDFS HA时,集群的会有几个NameNode进程? 解析: 搭建 过Apache Hadoop分布式集群(HDFS HA),就知道只有两个NameNode进程,一个是active,另外一个是standby。官方解释如图: http://www.cloudera.com/documentation/enterprise/5-5-x/topics/cdh_hag_hdfs_ha_intro.html

优秀的个人博客,低调大师

Excel COPILOT( ) 函数的10大应用场景2

场景描述:客户送修设备时一般会附带故障具体描述,服务人员需要按照既定故障分类标准,识别、匹配相关描述以判定故障类型,再将设备分派给对应工程师检修。但客户故障描述语言形式多样,依靠人工将其精准归入标准化故障分类体系,不仅难度大、耗费时间。引入智能自动化处理方案,能够有效提升故障归类的准确率与整体服务处理效率。

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册