如何从数组中获取子数组?

380

我有一个变量 var ar = [1, 2, 3, 4, 5],需要一个函数 getSubarray(array, fromIndex, toIndex),调用这个函数 getSubarray(ar, 1, 3) 的结果是一个新数组 [2, 3, 4]


10
你尝试过使用 slice 吗? - Tom Knapen
5个回答

571

请看Array.slice(begin, end)

const ar  = [1, 2, 3, 4, 5];

// slice from 1..3 - add 1 as the end index is not included

const ar2 = ar.slice(1, 3 + 1);

console.log(ar2);


68
这里可能值得明确提到的是,原始的 ar 没有被修改。console.log(ar);// -> [1, 2, 3, 4, 5] - daemone
2
还有一个错误不要犯,那就是混淆 slice() 方法和 splice() 方法:splice() 会改变原始数组,而 slice() 不会。 - Vladimir Fokow
抱歉,如果我尝试使用参数切片,会不会引发某种“索引超出范围”的错误?在这个例子中,如果我使用 ar.slice(4, 4);,会怎么样呢?我想我应该尝试一下 :x.. - Igor
2
@Igor 不会引发异常。如果 end 大于序列的长度,则切片提取到序列的末尾 (arr.length)。https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/slice - JM217
我想再补充一点,即slice对于任何类型的输入(字符串、未定义、对象等)都不会引发异常。如果start超出范围(负数或大于长度),它只会返回一个空数组。 - JM217

17

如果想要简单使用slice,可以使用我编写的数组类扩展:

Array.prototype.subarray = function(start, end) {
    if (!end) { end = -1; } 
    return this.slice(start, this.length + 1 - (end * -1));
};

那么:
var bigArr = ["a", "b", "c", "fd", "ze"];

测试1:

bigArr.subarray(1, -1);

< ["b", "c", "fd", "ze"]

测试2:

bigArr.subarray(2, -2);

< ["c", "fd"]

测试3:

bigArr.subarray(2);

< ["c", "fd","ze"]

对于来自其他语言(例如Groovy)的开发人员来说,可能会更容易理解。


24
不要修改你不拥有的对象 - Kartik Chugh
2
K_7所说的,尤其是对内置对象(Object、Array、Promise等)进行猴子补丁是非常不好的行为。可以看看著名的例子,比如MooTools强制重命名建议中的原生Array.prototype.containsArray.prototype.includes - daemone
2
更不用说,你的subarray方法提供了意外的结果。bigArr.slice(1,-1)返回['b','c','fd'],这是你所期望的(-1从新数组的末尾减去一个元素)。但是bigArr.subarray(1,-1)返回与bigArr.subarray(1)相同的结果,也就是从位置1到bigArr的末尾的所有内容。你还强制用户始终将负数作为end参数。任何end >= -1都会产生与end === undefined时相同的结果。另一方面,bigArr.slice(1,3)返回['b','c'],这也是预期的。 - daemone

7

精确解决方案

我有一个数组 var ar = [1, 2, 3, 4, 5],想要一个函数 getSubarray(array, fromIndex, toIndex),调用 getSubarray(ar, 1, 3) 后返回新的数组 [2, 3, 4]。

function getSubarray(array, fromIndex, toIndex) {
    return array.slice(fromIndex, toIndex+1);
}

测试解决方案

let ar = [1, 2, 3, 4, 5]
getSubarray(ar, 1, 3)

// result: [2,3,4]

Array.prototype.slice()

slice() 方法将数组的一部分浅拷贝到一个新的数组对象中。这部分被选中的数组从开始到结束索引(不包括结束索引)。起始和结束索引表示该数组中的项目索引,原始数组不会被修改。

基本上,slice() 让你从一个数组中选择一个子数组

例如,取这个数组为例:

const animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];

使用以下代码:

console.log(animals.slice(2, 4));

得到如下输出结果:

// 输出结果:["camel", "duck"]

语法:

slice() // creates a shallow copy of the array
slice(start) // shows only starting point and returns all values after start index
slice(start, end) // slices from start index to end index

查看浅拷贝参考资料


7

const array_one = [11, 22, 33, 44, 55];
const start = 1;
const end = array_one.length - 1;
const array_2 = array_one.slice(start, end);
console.log(array_2);


这里无法编译,修正如下: var array_one = [11, 22, 33, 44, 55]; var ar2 = array_one.slice(0, array_one.length-1); console.log(ar2) - bormat

1
这个问题实际上是在请求一个新数组,因此我认为更好的解决方案是将 Abdennour TOUMI's answer 与克隆函数结合起来:

function clone(obj) {
  if (null == obj || "object" != typeof obj) return obj;
  const copy = obj.constructor();
  for (const attr in obj) {
    if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
  }
  return copy;
}

// With the `clone()` function, you can now do the following:

Array.prototype.subarray = function(start, end) {
  if (!end) {
    end = this.length;
  } 
  const newArray = clone(this);
  return newArray.slice(start, end);
};

// Without a copy you will lose your original array.

// **Example:**

const array = [1, 2, 3, 4, 5];
console.log(array.subarray(2)); // print the subarray [3, 4, 5, subarray: function]

console.log(array); // print the original array [1, 2, 3, 4, 5, subarray: function]

[https://dev59.com/A3RB5IYBdhLWcg3wET5J]


10
我认为那个切片不会改变原始数组。 - Mani
10
Array.prototype.slice 返回一个副本。 Array.prototype.splice 修改原始数组。 - Guido Bouman
2
slice() 方法将数组的一部分浅拷贝到一个新的数组对象中。请参见 Mozilla 开发者网络。被踩了。 - TheCrazyProgrammer
正如其他人所说,slice 已经返回一个浅拷贝,使得这个 subarray 实现变得不必要。但值得一提的是,你已经对内置对象进行了猴子补丁操作,这是绝对不应该做的。请见 Abdennour TOUMI 的回答 上的评论。 - daemone

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