在任意维数组中搜索元素,并在搜索到的元素位置后插入一个指定元素

例如有一个4维数组:
arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
现要求写一个方法,查找这个数组中的元素8,并在第一次找到的8后面插入一个指定的值99;
调用该方法后,期望arr4的值会变成:
[1, 2, [3, 4, [5, 6, [7, 8, 99, [9, 10]]]]]

这个问题可以分为两个部分:

  1. 查找一个任意维数数组中的某个元素。
  2. 在任意维数数组中指定的索引中插入指定值。

第二个问题是比较直观的,只需要定义好索引的表示方法和利用迭代的数组访问方式就能解决。
我们定义一个n维数组A的某个元素的索引为一个数组I。这个I的元素索引为A的维度,从高到低排列。
而I的元素为A中对应维度的索引值。
例如,设有A = [1,2,3,[4,5,[6,7,8],6,7,10]],那么A中元素8的索引为I = [3,2,2]。

因此我们可以这么解决第二个问题:

//arr:目标数组,index:插入值所在索引,t:插入的值
function insertArray(arr, index, t) {
    let counter = 0;
    for (let idx of index) {
        if (counter === index.length-1) {
            arr.splice(idx, 0, t);
        } else {
            arr = arr[idx];
        }
        counter++;
    }
}
let A = [1, 2, 3, [4, 5, [6, 7, 8], 6, 7, 10]];
let I = [3, 2, 2];
insertArray(A, I, 8);
console.log(A); //[1, 2, 3, [4, 5, [6, 7, 8, 8], 6, 7, 10]]

回到第一个问题,我们需要一个方法,输入一个任意维数的数组和一个元素的值,返回一个表示该元素在数组中的索引的数组。
由于这是一个对任意深度的数组的搜索,我们可以用递归的思维解决。记录每次进入更低维度时的索引值。

function searchArray(arr, target) {
    let isDone = false;
    let index = [];
    function search(arr, target) {
        // index = index || [];
        for (let i = 0; i < arr.length; i++) {
            if (isDone) return;
            if (arr[i] !== target) {
                if (arr[i] instanceof Array) { //如果可以进入下一维度,则进去搜索
                    index.push(i);
                    search(arr[i], target);
                }
                else if (i === arr.length - 1) { //在当前维度找不到目标时,退回上一维度
                    index.pop();
                }
            }
            else {
                index.push(i);
                isDone = true;
            }
        }
    }
    search(arr,target);
    return index;
}

let A = [1, 2, 3, [4, 5, [6, 7, 8], 6, 7, 10]];
let index = searchArray(A, 8);
console.log(index); // [3, 2, 2];

这么写个人觉得非常丑,为了把两个标志变量包含进函数里,我在递归函数外面又套了一层函数。我相信一定有方法可以把返回信息从递归内层传回外层的。不管怎么样我们算是把问题解决了。

我们也可以把两个问题一次性解决掉。因为在我们搜索元素的时候,可以顺便把要插入的值插到数组中,但是我们要注意在数组插入值以后,就要停止搜索返回,或者跳过插入值继续搜索后面的元素。不然如果插入的值跟搜索目标一样时,插入操作将会没完没了。

function searchArray(arr, target, value) {
    for (let i=0; i < arr.length; i++){
        if (arr[i] !== target) {
            if (Array.isArray(arr[i])) {
                searchArray(arr[i], target, value);
            }
        } 
        else {
            arr.splice(i+1, 0, value);
            return; //或 i++; 这样写只能限定每个维度只插入一次,如果不同维度中都出现目标,则会在每个维度的目标后都会插入value。因为这个return只能回到上一层递归,而不能返回所有递归调用。
        }
    }
}
let arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
searchArray(arr4, 8, 8)
console.log(arr4); //输出:[1, 2, [3, 4, [5, 6, [7, 8, 8, [9, 10]]]]]

为了确保只插入一次,我只能又用这种丑陋的写法:

function searchArray(arr, target, value) {
    let isDone = false;
    function search(arr, target, value) {
        for (let i = 0; i < arr.length; i++) {
            if (isDone) return;
            if (arr[i] !== target) {
                if (Array.isArray(arr[i])) {
                    search(arr[i], target, value);
                }
            }
            else {
                arr.splice(i + 1, 0, value);
                isDone = true;
            }
        }
    }
    search(arr,target, value);
}

let arr4 = [1, 2, 3, [4, 5, [6, 7, 8], 6, 7, 8, 10]];
searchArray(arr4, 8, 8)
console.log(arr4); //输出:[1, 2, 3, [4, 5, [6, 7, 8, 8], 6, 7, 8, 10]]
posted @ 2021-12-20 02:55  zipeilu  阅读(72)  评论(0编辑  收藏  举报