多维数组取值问题

问题简述

给予一个多维数组和一个描述取值路径的一维数组, 通过调用函数f返回取值路径描述的值,如 f([[1, 2], [3, 4], [5, 6]], [0, 0]) -> 1

原问题传送门

之所以想记录一下是因为之前有在codewars刷题的习惯,后来工作忙就怠慢了,今天闲来无事就准备刷几道玩玩,然后就挑了一个比较简单的7kyucodewars中的难度评级)的题。

因为这题比较简单,我也没多想,上来就干,仔细想了下,很容易嘛,不就是递归吗?按大学老师教的来一套:

  • 先找递归退出的条件,当路径取到最后或者目标数组已经取尽(这里似乎题目没有说清楚,暂定不对取值路径做限定吧)
  • 再找递归的模式, 如果不满足递归退出的条件,则将目标数组缩小一维,传递新的取值路径并递归

然后就有了第一版代码

function getElement(array, indexes) {
  const idx = indexes.shift()
  
  if(indexes.length === 0 || array[idx].constructor !== Array ) return array[idx]
  else return getElement(array[idx], indexes)
}

然后跑了跑作者提供的简单测试用例,all passed,我就说嘛,这么简单的题目不一把过岂不是有点丢脸,然后就直接点了提交,然后就蹦了一大片的failed测试用例出来,仔细看了看失败的测试用例,并没有看懂,因为都是很多莫名奇妙的数据,并且每次返回的结果都不一致(后来才知道是随机的用例)。

之后一直以为是自己有一些边界情况没有考虑到,就前前后后又看了几次自己的答案,并没有发现什么大的问题,但是无论怎么提交都是失败。之后前前后后大概看了15分钟左右,突然就觉得是我自己把问题想简单了。

因为最近一直在看函数式的东西,突然就联想到,自己写的这个函数,并不。关于纯函数是函数式编程中最基本的概念之一,所谓纯既是要求函数没有副作用,我这里的getElement使用了Array.shift方法,会对原数组进行修改,从而产生副作用。这么一想一下就和之前每次跑用例总是产生意想不到的结果的情况联系上了,随机用例的失败原因一定是因为测试路径会有很多个,但是测试目标数组只有一个,因此有副作用的话,只有第一次测试的结果是正确的,后面都会因副作用产生不同的结果。

既然是因为数组是引用类型而产生的问题,那么直接来一个深拷贝就可以了。因为这里只是答题,所以使用一个最简单粗暴的深拷贝大法x => JSON.parse(JSON.stringify(x)),然后代码就有了第二版代码

function getElement(array, indexes) {
  array = JSON.parse(JSON.stringify(array))
  indexes = JSON.parse(JSON.stringify(indexes))
  
  const idx = indexes.shift()
  
  if(indexes.length === 0 || array[idx].constructor !== Array ) return array[idx]
  else return getElement(array[idx], indexes)
}

之后提交,所有的用例都通过了。但是还没有结束,因为自己的代码在实现上还是挺啰嗦的,同时还使用了深拷贝大法,有没有更简单的方法呢?

有的。如果仔细思考一下,这里的解题的思路其实和Array.reduce的模式很像

  • 对一个数组进行遍历(对路径数组进行遍历)
  • 每次遍历返回一个值,并作为参数传入下一次遍历(对目标函数的降维)
  • 在遍历完成后,返回一个结果(取值路径对应的值)

因此利用Array.reduce,这个问题一行代码就可以解决,如下

function getElement(array, indexes) {
  return indexes.reduce((a, i) => a[i], array);
}

同样多考虑一下,它是纯函数吗?是的,它是纯的。因为这里只做了取值的操作(a[i]),并不涉及任何的修改原数组的操作。这个答案也是在我提交后,所有答案中实现方案最好的一个。

当然还有其他的暴力破解法,我觉的想法也不错,比如

function getElement(array, indexes) {
  return eval(`array[${indexes.join("][")}]`);
}

还有利用spread运算符的方法,如

const getElement = (array,[index,...moreIndices]) => moreIndices.length ? getElement( array[index], moreIndices ) : array[index]

所以工作累了,或者闲来无事,刷刷题还是挺有意思的,可以看见一些自己平时很熟悉但是在需要用时又难以想起的知识。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏AI深度学习求索

算法图解(五)|散列表与字典

我们之前介绍过简单查找和二分查找,简单查找是从头开始一个个查找,二分查找是在有序列表中按分而治之的思想进行查找,虽然二分查找已经很快速了,但是在有些情况下,还是...

14410
来自专栏python学习之旅

算法学习笔记(一):插入排序和线性查找

11730
来自专栏阿凯的Excel

文本数字拆分技巧(第二弹!)

上期刚刚分享了简单的通过智能填充和Len与LenB函数实现的文本数字拆分! 感兴趣可以点我先看上一期的! 本期难度较上期略有提高,和您分享新的技巧。 ? 没...

30670
来自专栏CDA数据分析师

10个应该早点知道的Python技巧

我的这一生都在编程,但是我没有成为一名程序员。最初,我的大部分工作都是用Visual Basic来完成的,还包括一些其它语言工具,比如R语言,C语言、JavaS...

30690
来自专栏林德熙的博客

C# Find vs FirstOrDefault

需要知道,两个方法都是 Linq 的方法,使用之前需要引用 Linq 。对于 List 等都是继承可枚举Enumerable这时获取第一个元素可以使用First...

19110
来自专栏Java学习网

10种简单的Java性能优化学习

10种简单的Java性能优化学习 你是否正打算优化hashCode()方法?是否想要绕开正则表达式?Lukas Eder介绍了很多简单方便的性能优化小贴士以及扩...

35860
来自专栏猿人谷

oc 中随机数的用法(arc4random() 、random()、CCRANDOM_0_1()

1)、arc4random() 比较精确不需要生成随即种子        使用方法 :                  通过arc4random() 获取0到...

25280
来自专栏康怀帅的专栏

Shell date 命令详解

以给定的格式显示当前时间。 %% 一个文字的 % %a 当前locale 的星期名缩写(例如: 日,代表星期日) %A 当前locale 的星...

38140
来自专栏葡萄城控件技术团队

5分钟掌握var,let和const异同

这个话题对于一些老鸟来说可能根本算不上疑问,但对于新手来说也许除了最常见的var之外,let和const较少使用的机会。

15350
来自专栏高性能服务器开发

API设计原则 – QT官网的设计实践总结

原文链接:API Design Principles – Qt Wiki 链接:(http://wiki.qt.io/API_Design_Principles...

32220

扫码关注云+社区

领取腾讯云代金券