在JavaScript中反转数组

4

我有一个名为reverseArray的JavaScript函数,它以数组作为参数,并返回一个新的数组,该数组与输入数组具有相同的值但是顺序相反。我想创建一个名为reverseArryInPlace的函数,它可以将输入数组的值改为相反的顺序。

function reverseArray(inputArray) {
  var outputArray = [];
  for (var i = inputArray.length - 1; i >= 0; i--)
    outputArray.push(inputArray[i]);
  return outputArray;
}

function reverseArrayInPlace(inPlaceInputArray) {
  inPlaceInputArray = reverseArray(inPlaceInputArray);
  console.log('Inside reverseArrayInPlace: ' + inPlaceInputArray);
  return inPlaceInputArray;
}

var arrayValue = [1, 2, 3, 4, 5];
reverseArrayInPlace(arrayValue);
console.log('Outside reverseArrayInPlace: ' + arrayValue);
// Expected Value: [5, 4, 3, 2, 1]

这是我执行这段代码时得到的结果:
Inside reverseArrayInPlace: 5,4,3,2,1
Outside reverseArrayInPlace: 1,2,3,4,5

在reverseArrayInPlace函数中,arrayValue变量已按预期进行了反转。为什么当我在reverseArrayInPlace函数之外引用同一变量时,它又回到了原始顺序?


2
如果这是一道作业题,那也无妨;它具备了一个好问题的所有特质。 - Hanky Panky
1
你认为你的代码中的 "InPlace" 部分发生在哪里? - Felix Kling
1
你的 reverseArrayInPlace() 方法并没有真正地 原地 反转数组,而是创建了一个新的数组(这不是 原地)。要实现 原地 反转,请交换原始数组中的元素,而不是创建一个新数组。 - Jean-Baptiste Yunès
你可以使用Array.reverse()函数。 - Azad
这是来自《JavaScript编程精解》一书的问题,但它并不是作业,因为我已经不在学校了。 - AGP
哈哈,这完全不是问题。 - user4074041
4个回答

2

如果你想要原地反转它,那么你必须在原地反转它。

function reverseArrayInPlace(array) {
  for (let i = 0, j = array.length - 1; i < j; i++, j--) 
    [array[i], array[j]] = [array[j], array[i]];
}

const a = [1,2,3,4,5];
reverseArrayInPlace(a);
console.log(a);


好的,你能解释一下[x,y]=[y,x]语句中发生了什么吗? - user4074041
[a, b] = [b, a] 使用数组解构赋值交换了 ab 的值。详见 数组解构赋值 - user663031
1
为什么当你重新分配数组的单个索引时,全局变量(a)会改变,但是当我重新分配整个数组时,全局变量不会改变? - AGP

1
这里的根本问题在于JavaScript中的原始类型是按值传递的。有关详细信息,请参阅以下问题: Javascript按引用传递还是按值传递 以下是一个尝试更改传递给它的字符串的函数的简单示例:
var outsideValue = 'foo'

function mutate(value) {
  value = 'fish'
}

mutate(outsideValue);
console.log(outsideValue);

然而,控制台输出为foo

这是因为mutate函数内的value变量是一个在函数初始调用时引用outsideValue的变量。当它在函数体内被赋新值时,它仅仅更改了value变量所引用的新字符串。结果是,outsideValue没有受到影响。

查看此答案以获取一个原地反转的示例:

https://dev59.com/d6Hia4cB1Zd3GeqPMwRh#43486686

请注意,它不会重新分配函数参数。

1
基本类型按值传递,value 没有引用 outsideValue 的值,它只有该值的副本。如果该值是一个引用(指向对象),那么它们将引用同一个对象。但在这种情况下,该值是一个引用,而不是一个基本类型。;-) - RobG
所以现在我明白,通过重新指定数组参数,我实际上并没有改变全局变量。但是在示例答案中,我们改为重新指定数组参数的各个索引。为什么这样做时全局变量会更改? - AGP
@AGP,这就是对象引用和原始值之间的区别。原始值无法更改,只能通过覆盖(使用新值)来更改保存它们的变量。每次将它们分配给新变量时,它们都会被传递为副本。对象作为引用传递。在幕后,内存中的地址指向该对象的位置。如果我更改对象的某个属性,则对象本身会更改,因此所有知道该对象的人都“拥有”此更改。 - Thomas

0

正如其他人所说,数组是对象,因此它们是通过引用传递的。您必须修改原始数组,而不是创建新数组。

因此,这里有另一个版本的reverseInPlace,它使用shift从数组中删除最后一个元素,并使用splice将其插入到新位置:

function reverseInPlace(arr) {
  var i = arr.length;
  while (i--) {
    arr.splice(i, 0, arr.shift());
  }
}

var arr = [1,2,3,4,5];
console.log('Before: ' + arr.join());

reverseInPlace(arr);
console.log('After:  ' + arr.join());

如果想要一些乐趣,您也可以利用sort

NB:这仅适用于某些浏览器,它取决于内置的排序算法,这是实现相关的。

function reverseInPlace(arr) {
  arr.sort(() => 1);
}

var arr = [47, 95, 80, 62, 8, 34, 31, 17, 62, 17, 85, 72, 51, 20, 68, 60, 30, 84, 7, 34];
console.log('Before: ' + arr.join());

reverseInPlace(arr);
console.log('After : ' + arr.join());


很遗憾,你的“fun”版本不起作用。它依赖于内部排序算法和调用排序函数的顺序。为了验证这一点,请尝试类似于 Array.from({length: 100}, _ => Math.floor(Math.random() * 100)).sort(() => 1) 的代码。 - user663031
@torazaburo—它在Firefox 38中“可以工作”(但在IE中失败)。;-) 我有疑问,很高兴得到确认我的怀疑是正确的。 - RobG
我认为这与浏览器根据数组大小切换到不同的算法有关。 - user663031

-2
function reverseArray(inputArray) {
  var outputArray = [];
  for (var i = inputArray.length - 1; i >= 0; i--)
    outputArray.push(inputArray[i]);
  return outputArray;
}

function reverseArrayInPlace(inPlaceInputArray) {
  inPlaceInputArray = reverseArray(inPlaceInputArray);
  console.log('Inside reverseArrayInPlace: ' + inPlaceInputArray);
  return inPlaceInputArray;
}
var arrayValue = [1, 2, 3, 4, 5];
**arrayValue = reverseArrayInPlace(arrayValue);**
alert('Outside reverseArrayInPlace: ' + arrayValue);
// Expected Value: [5, 4, 3, 2, 1]

//

你的代码是正确的,只需要替换一行并写上 arrayValue = reverseArrayInPlace(arrayValue); 而不是 reverseArrayInPlace(arrayValue); 然后arratValue将打印出预期的值


然后,我们需要添加新的变量并打印它,而不是像这样打印数组值: var reversedValue = reverseArrayInPlace(arrayValue); 然后打印这个新值 alert('Outside reverseArrayInPlace: ' + reversedValue); - NEO
你没有完全理解“原地”(in place)的含义。 - user663031
请使用此函数 reverseArray(inputArray) { var outputArray = []; for (var i = inputArray.length - 1; i >= 0; i--) outputArray.push(inputArray[i]); return outputArray; }function reverseArrayInPlace() { arrayValue = reverseArray(arrayValue); console.log('在 reverseArrayInPlace 内部:' + arrayValue); } var arrayValue = [1, 2, 3, 4, 5]; reverseArrayInPlace(arrayValue); alert('在 reverseArrayInPlace 外部:' + arrayValue); // 预期值:[5, 4, 3, 2, 1] - NEO
不需要使用inPlaceInputArray数组变量,只需在reverseArrayInPlace函数中使用arrayValue即可。但仍然需要将reverseArray函数的值分配给arrayValue,例如:arrayValue = reverseArray(arrayValue); - NEO
不要误解,但如果您不理解问题中的术语,最好不要写答案。OP想要在原地反转数组。他们已经知道通过创建新数组如何实现它。以任何方式展示如何做同样的事情都没有帮助。 - JJJ
显示剩余3条评论

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