不确定为什么此函数返回反向数组

时间:2018-11-10 21:06:14

标签: javascript arrays

我正在从事JavaScript练习,但在弄清逻辑为何起作用时遇到了一些麻烦。它基本上具有一个称为“神秘”的函数,该函数使用许多非常简单的函数,并以相反的顺序返回您提供的数组。我已经在白板前坐了一个小时,试图弄清楚背后的逻辑,但没有理解。善良的灵魂可以看看这些功能并解释神秘功能如何返回反向数组吗?谢谢!

LinkListControlToField1.Active := true;

8 个答案:

答案 0 :(得分:2)

神秘是一个递归函数。

它使用rest函数的返回值进行自身调用,该函数返回除第一个元素以外的所有内容。

它使用that的结果+ first的结果,该结果返回第一个字符,并再次连接它们(使用conj),但第一个元素结尾。

所以,假设您输入了[H e l l o],

它将返回conj(mystery([e l l o], H)

mystery([e l l o])将返回conj(mystery([l l o], e)

mystery([l l o])将返回conj(mystery([l o], l)

依此类推,直到进入mistery的数组为空,在这种情况下递归结束,然后我们冒泡回到第一个调用。

请注意,递归经常用于这样的练习,但是尽管它有一些特定的用途,但在许多情况下,不使用递归会更有效,因为与调用该函数相比,进行另一个函数调用的开销相对比较大。其他解决方案使用一个简单的循环来移动或交换项目。

如果您输出一些信息,您可以看到正在发生的事情:

function rest(arr) {
  return arr.slice(1);
}


function first(arr) {
  return arr[0];
}

function conj(arr, value) {
  arr.push(value);
  return arr;
}

function mystery(array, level) {
  if (array.length === 0) {
    console.log('mystery level '+level+' is called with an empty array. Recursion ends here.. Stay tuned for the answer.');
    return [];
  }
  console.log('mystery level '+level+' is called with '+array+
              '. I will move '+first(array)+' to the end.');
  
  var result = conj(mystery(rest(array), level+1), first(array));
  console.log('returning '+result+' for level '+level);
  return result;
}

console.log(mystery(['H','e','l','l','o'], 0));

答案 1 :(得分:1)

要了解使用递归的函数,可以暂时假设 recursive (嵌套)调用返回其应有的内容,然后查看其构建方式从而产生正确的结果。

例如,假设array[1, 2, 3, 4]

所以这行:

 conj(mystery(rest(array)), first(array));

...的递归调用为mystery。它以array作为参数,但是删除了第一个元素(即rest返回的内容),因此它得到了[2, 3, 4]

现在,我们仅假设对mystery的递归调用做正确的事情并将该数组反转为[4, 3, 2]。然后,在上面引用的代码中,我们看到此结果与first(array)(这是第一个值,即1)连接在一起。这样我们得到[4, 3, 2, 1]。正确!

这告诉我们,如果我们假设mystery对具有n-1个值的数组执行正确的工作,那么对n个值也适用。

现在需要看看mystery是否能正确处理最小的情况,即数组为空。在这种情况下,很容易看到它返回了正确的结果,即一个空数组。

因此,将这两件事放在一起,您会发现mystery对于所有可能的数组大小都能正确完成工作。

答案 2 :(得分:1)

您的第一个函数“ rest”将删除第一个元素,因为slice将把元素从1返回到数组的末尾,然后“ conj”函数将采用被删除的第一个元素(通过“ first”函数)并将其放在最后,然后递归执行,它将从一开始就将元素放到最后。

答案 3 :(得分:1)

.push方法将该项放置在数组的末尾。 .slice(1)的意思是“第一项除外”

伪代码

  1. 获取数组A(mystery的arg)。如果为空,则返回
  2. rest(除第一个以外的所有东西)。我们将其余的称为B
  3. 在B上运行该程序(递归)
  4. 将A的第一项附加到B的末尾

conj =将value附加到arr

first =获得arr的第一项

rest =返回除第一项以外的所有内容

mysteryarray为空时=返回空数组

mystery,当array不为空时=取rest(array),对其运行mystery,然后附加数组first

答案 4 :(得分:1)

是的,递归的魔力。要理解,想一想如果您用2元素数组mystery调用[1,2]会做什么。

rest(array)将是[2] mystery(rest(array))还将是[2]

first(array)将是1

然后您返回conj([2], 1),这会导致[2,1]

现在的诀窍是递归。如果您有3个元素[0,1,2]并用它来称呼奥秘,那就会发生:

  • 它将调用mystery(rest(array)),其本质上是mystery([1,2])。我们已经看到了返回[2,1]的结果。
  • first(array)将是0
  • 因此它返回conj([2,1],0),逻辑上是[2,1,0]

现在,它可以根据需要为任意多个元素提供支持。本质上,每个元素都将调用mystery,以将其放置在所有元素之后。

答案 5 :(得分:1)

这里要注意的一件事是mystery()是递归调用的。我添加了一些注释来说明每个步骤的进展。

function rest(arr) {
  console.log('take first n-1 elements of', arr);
  return arr.slice(1);
}


function first(arr) {
  return arr[0];
}

function conj(arr, value) {
  arr.push(value);
  console.log('combine', arr, 'with', value)
  return arr;
}

function mystery(array) {
  console.log('call mystery on ', array)
  if (array.length === 0) {
    return [];
  }
  return conj(mystery(rest(array)), first(array));
}

mystery([0,1,2])

答案 6 :(得分:1)

这很简单。您无法看到它的原因是 RECURSION 。我希望您注意几件事:

  • mystery(array)是递归函数,因为它会自行调用,直到传入的数组为空为止
  • 您所有的工作都在这里进行: 返回conj(mystery(rest(array)),first(array));

在这里,我将不讨论递归函数,而是向您展示如何使用 console.log()跟踪每个递归调用。在下面查看我的代码,我添加了console.log()以使您更加清楚。尝试运行一些数组的奥秘并查看结果。这对您来说很有意义。

function rest(arr) {
  return arr.slice(1);
}


function first(arr) {
  console.log("Returning ",arr[0], "from first(arr).")
  return arr[0];
}

function conj(arr, value) {
  console.log("Pushing ",value, " to ",arr, " in conj(arr,value)");
  arr.push(value);
  console.log("Returning ",arr, " from Conj(arr,value)");
  return arr;
}

function mystery(array) {
  if (array.length === 0) {
    console.log("array is emplty. So, returning empty array from mystery");
    return [];
  }
  console.log("array is not emplty. So, calling mystery(array) again.");
  return conj(mystery(rest(array)), first(array));
}
var reverse =mystery([1,2,3,4]);
console.log("The final result", reverse);

答案 7 :(得分:0)

不会说谎,这是一种颠倒数组顺序的怪异方法。它基本上是使用递归来对数组的第一个元素进行切片,并将元素与最后一个元素合并在一起。

所以这里是散步:

mystery(['h','e','l','l','o'])->

首先检查数组是否为空,然后调用方法rest->

rest(['h','e','l','l','o'])->

rest将索引1处的数组切成片,返回['e','l','l','o']->

的新数组

然后调用mystery,它以返回值rest->

重复前面的步骤。

mystery(['e','l','l','o'])->

这意味着直到rest返回一个空数组->

之前,奥秘都会不断被唤起。

mystery(['e','l','l','o'])->
mystery(['l','l','o'])->
mystery(['l','o'])->
mystery(['o'])->
mystery([])->

当谜题有一个空数组时,它将返回该空数组,然后将first称为->
首先返回数组的第一个元素,并在返回神秘值之后发生,在返回神秘值之前它看起来像这样->

mystery(['e','l','l','o']) , first(['h','e','l','l','o'])->
因此,在最低级别,当mystery返回一个空数组并首先返回['o']中的第一个元素时,它看起来像这样->

[] , ['o']->
conj将使用这些值->
conj([] , ['o'])->
conj返回两个值的组合->
conj([] , ['o'])->
['o']->
然后返回并重复->
conj([] , ['o'])->
conj(['o'] , ['l'])->
conj(['o','l'] , ['l'])->
conj(['o', 'l','l'] , ['e'])->
conj(['o', 'l','l', 'e'] , ['h'])->
['o', 'l','l', 'e','h']