reverseArrayInPlace()无法正常工作

3
有其他关于这个问题的问题,但我想知道为什么我的代码不能反转给定的数组。注意:我非常新手,只是自学并尝试为个人兴趣练习。
在书Eloquent Javascript中,我们被要求编写两个不同的函数来反转一个数组。第一个函数reverseArray应该输出一个新的数组,它是给定数组的反转。那个很容易。
第二个函数reverseArrayInPlace应该改变给定的数组,使其反转。假设仅使用第一个函数,然后将其值分配给第一个数组是“作弊”的。此外,我们不能使用.reverse方法。
这是我的尝试,我无法弄清楚为什么它不起作用:
var reverseArrayInPlace = function(anArray) {
    for (var i = 1; i < anArray.length; i++) {
        anArray = anArray.slice(i, i+1).concat
        (anArray.slice(0,i)).concat(anArray.slice(i+1));
    }
}

注意:我不喜欢我写的这个函数,但是仍然无法确定为什么它不起作用。
以下是书中给出的测试代码和目标输出:
var arrayValue = [1, 2, 3, 4, 5];
reverseArrayInPlace(arrayValue);
console.log(arrayValue);
// → [5, 4, 3, 2, 1]

书中给出的提示是:
诀窍是交换第一个和最后一个元素,然后交换第二个和倒数第二个元素,以此类推。你可以通过循环数组长度的一半来实现这一点(使用Math.floor向下取整——在长度为奇数的数组中不需要触摸中间元素),并将位置i处的元素与位置array.length-1-i处的元素互换。您可以使用一个本地变量暂时保存其中一个元素,用其镜像图像覆盖该元素,然后将本地变量的值放回镜像图像曾经所在的位置。
我不喜欢我的想法,但我更不喜欢这个提示。是否有更符合“原地”更改数组精神的方法比我的想法更好?
感谢您的帮助。再次提醒,我们不能只使用所给数组上的.reverse。

for循环的主体是一行代码吗?问题出在第一行到第二行使用了两次.concat方法吗? - Dave Cousineau
你有检查控制台吗? 你的代码有很多错误。但是要找到问题的根源,你不能只创建一个数字数组(这就是sliceconcat所做的),如果你想改变一个现有的数组。 - Mike Cluck
每次调用.slice()都会创建一个新的数组。这似乎与原地反转的精神相去甚远。 - Pointy
现在,这是关于在SO上提出好的首次问题的方法。祝你好运! - Flummox - don't be evil SE
3个回答

1
虽然这不是最短的解决方案,但我尽力让它易于理解。基本上,我们在数组中创建两个索引指针left和right,其中left从第一个元素开始,right从最后一个元素开始。因为我们不需要交换中间值,所以在while循环内进行left < right的简单检查将使其在到达中间值之前停止。然后,我们使用tmp变量作为临时占位符来交换项目,在此之后,我们可以增加左侧并减少右侧索引指针。为了使其成为原地替换,我们使用索引数组访问方法,使用[]而不是slice等。

var reverseArrayInPlace = function(anArray) {
  var left = 0, right = anArray.length - 1, tmp;
  while (left < right) {
    tmp = anArray[left];
    anArray[left] = anArray[right];
    anArray[right] = tmp;    
    left ++;
    right --;
  }
}

var a = [1,2,3,4,5];

reverseArrayInPlace(a);

console.log(a);


0

我看到两个错误:

第一个错误是您重复调用了concat

var reverseArrayInPlace = function(anArray) {
   for (var i = 1; i < anArray.length; i++) {
      anArray = anArray.slice(i, i+1).concat // two concats! one here and one on next line
      concat(anArray.slice(0,i)).concat
      (anArray.slice(i+1));
   }
}

另一个错误是您没有返回任何内容。更正后的函数如下所示:
var reverseArrayInPlace = function(anArray) {
   for (var i = 1; i < anArray.length; i++)
      anArray =
         anArray
         .slice(i, i + 1)
         .concat(anArray.slice(0, i))
         .concat(anArray.slice(i + 1));

   return anArray;
};

请注意,这并不是一个“原地”反转。在得到最终结果之前,此代码将生成许多中间数组。真正的原地反转会有很大不同,可能会交换元素。

根据要求,一种可能性是从末尾与开头的元素交换,停在中间。交换通常需要使用临时变量,这也可以被视为“原地”违规。

为了完全原地进行操作,即使没有临时变量,也可以使用异或技巧来交换元素。但这只适用于数字,而不适用于对象等其他类型。您也不想以这种方式交换中心元素(如果有的话),因为这样会将其清零。

// tricky way to swap two elements (assumes front != back)
anArray[front] ^= anArray[back];
anArray[back]  ^= anArray[front];
anArray[front] ^= anArray[back];

这不会修改原始数组,而是创建一个新的数组。 - Mike Cluck
@MikeC 是的,这不是“原地反转”,但问题是“为什么这段代码不起作用”。 - Dave Cousineau
没错,它没有原地反转数组。这就是出问题的部分。 - Mike Cluck
@MikeC,好的,不是的,他说有问题的部分是它甚至没有翻转数组。这个函数命名错误。纠正后,现在可以反转数组了。它实际上并不是原地反转数组很重要,但不是实际问题的一部分。 - Dave Cousineau
他们说他们的创建一个新数组的解决方案是有效的,但是他们无法让它们的原地解决方案起作用。 - Mike Cluck
@MikeC 好的,我已经解释了它不在原地的问题,描述了如何在原地进行操作,并给出了一个小例子。除非完全为他编写代码,否则这就是我能做的一切。 - Dave Cousineau

0

Your code is working when you walk until the end of the array (array.length + 1) and when you return the new array.

var numbers = [1, 2, 3, 4, 5, 6];

var reverseArrayInPlace = function(arr) {
  for (var i = 1; i < arr.length + 1; i++) {
    arr = arr.slice(i, i + 1).concat(arr.slice(0, i)).concat(arr.slice(i + 1));
  }
  return arr;
}

var r = reverseArrayInPlace(numbers);
console.log(r);

但问题是如何根据其他标准来逆转已使用的数组。


书中的提示几乎给出了解决方案。

它涉及到:

  • 交换
  • 数组长度的一半
  • array.length - 1 - i

交换

var n = [4, 9];
var temp = n[0]; // Assign left to a temporary (locale) variable for a "briefly hold"
n[0] = n[1]; // Assign right to left
n[1] = temp; // Assign the temporary variable (left) to right
console.log(n);

数组长度的一半

var half = Math.floor(arr.length / 2); 

使用 Math.floor。它可以捕获长度为奇数的数组

Math.floor(7 / 2) -> 3

总共

var numbers = [1, 2, 3, 4, 5];

function reverseArrayInPlace(arr) {
  var half = Math.floor(arr.length / 2);
  for (var i = 0; i < half; i += 1) {
    // Swap start
    var temp = arr[i];
    arr[i] = arr[arr.length - 1 - i];
    arr[arr.length - 1 - i] = temp;
    // Swap end
  }
}

reverseArrayInPlace(numbers);
console.log(numbers);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接