用同一个元素重复多次创建一个数组

625

在Python中,其中[2]是一个列表,下面的代码会产生以下输出:

[2] * 5 # Outputs: [2,2,2,2,2]

有没有使用JavaScript数组来轻松实现这个的方法?

我写了下面的函数来实现它,但是有更短更好的方法吗?

var repeatelem = function(elem, n){
    // returns an array with element elem repeated n times.
    var arr = [];

    for (var i = 0; i <= n; i++) {
        arr = arr.concat(elem);
    };

    return arr;
};

4
可能重复:https://dev59.com/hnM_5IYBdhLWcg3wn0vT - Larry Battle
25个回答

1260

在 ES6 中使用 Array 的 fill() 方法

console.log(
  Array(5).fill(2)
)
//=> [2, 2, 2, 2, 2]


3
目前,Internet Explorer和Opera尚不支持它。 - DenisKolodin
4
Node.js <= 3 不支持此功能。 - Junle Li
2
对于那些缺乏支持的人,已经存在一个polyfill - JohnnyQ
17
@Michael,你可以使用Array(5).fill([1,2,3]).flat()来实现。请注意,flat()方法仍处于实验阶段,浏览器支持较差。 - Niko Ruotsalainen
36
请注意,fill方法的参数只会被评估一次,因此 Array(9).fill(someMutable) 在数组中创建了九个对 someMutable 的引用(对一个进行修改会将所有引用都进行修改)。 - Carl Smith
显示剩余5条评论

181
>>> Array.apply(null, Array(10)).map(function(){return 5})
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
>>> //Or in ES6
>>> Array.from({length: 10}, () => 5)
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5]

13
这是一个愚蠢的问题,但为什么new Array(10).map不起作用? - blazkovicz
2
blazkovicz,查看zertosh在此答案上的评论以了解原因。 - Ross Rogers
9
通过使用 ES6,可以使用扩展运算符将Array(...Array(10)).map(() => 5)进行“升级”,也可以使用Array.from(Array(10)).map(() => 5)。这样做可以使代码更加简洁,并且在结果上与原来的代码相同。 - Christophe Vidal
10
根据MDN的说明,您可以这样做:Array.from({length: 10}, () => 5); - Preco Plusb
5
@blazkovicz Array(10)创建一个长度为10的数组,没有任何可枚举的属性。.map只能用在可枚举的属性上。.apply方法将这个数组映射到一个arguments array(类似数组的对象),以便传递给Array构造函数。由于参数数组不能是稀疏的,因此缺失的属性被设置为undefined并变成了可枚举。现在我们可以像预期一样使用.map - CervEd
显示剩余2条评论

131

你可以尝试:

Array(6).join('a').split(''); // returns ['a','a','a','a','a'] (5 times)

更新(2018年1月6日):

现在您可以拥有一组可重复的字符。

new Array(5).fill('a'); // give the same result as above;
// or
Array.from({ length: 5 }).fill('a')

注意:了解有关fill()from()的更多信息,以了解其兼容性和浏览器支持。

更新(2019年5月11日)

另一种用于任意长度字符串的方法,而不使用fillfrom

Array.apply(null, Array(3)).map(_ => 'abc') // ['abc', 'abc', 'abc']
同上面答案。为了完整起见添加。

2
不错。最短和简单的。 - Johann Echavarria
2
+1 对于简单处理。很遗憾你不能从中创建一个空字符串数组。除此之外非常聪明... - Quicker
1
Array(6).join('a').split('a') 会给我一个空字符串的数组。 - Vivek
20
这仅适用于单个字符的字符串,因此并不能完全回答这个问题。 - az_
每个“a”是单独的对象吗?还是它们引用同一个对象? - Al V
3
@AlfonsoVergara:在Javascript中,String是一种基本(值语义)类型;没有办法让两个字符串引用相同的数据(因为在Javascript中字符串不是引用,它们是值)。你必须注意对象和列表的引用语义,但不需要关注字符串。 - Quuxplusone

116

...而Array.fill()大显身手!

在知道这个方法之前,我们都是手动写的 ‍♂️

Array(5).fill('')  // =>  ['','','','','']

Array(4).fill(0)  // =>  [0, 0, 0, 0]

你还可以使用 fill() + map() 轻松创建一个顺序数组


Array(4).fill('').map((_, i) => i + ' ') // =>  ['0 ','1 ','2 ','3 ']


Array(3).fill(' ').map((flower, i) => i + flower) // =>  ['0 ','1 ','2 ']


❗️使用 .fill() 创建对象和数组时请小心,它们是引用类型❗️

这意味着 JavaScript 将所有创建的项目视为同一个对象(如果您想进一步与创建的对象交互,则可能会引入意外错误)


//  Careful when using .fill() with objects and arrays:

Array(3).fill({ value: 2 })  // =>  [{ value: 2 },{ value: 2 },{ value: 2 }]

以上代码可以工作,但最好还是坚持使用.fill().map()的方式。像这样:

//  Much better!

Array(3).fill().map(item => ({ value: 2 }))

请注意,IE不支持它,但您可以使用polyfill。 - Yihao Gao
11
我猜IE不支持很多东西... :) - Felipe Chernicharo

72

你可以这样做:

function fillArray(value, len) {
  if (len == 0) return [];
  var a = [value];
  while (a.length * 2 <= len) a = a.concat(a);
  if (a.length < len) a = a.concat(a.slice(0, len - a.length));
  return a;
}

它每次迭代都会将数组加倍,因此可以通过少数迭代创建一个非常大的数组。


注意:您还可以通过使用push而不是concat来大大改进函数,因为concat会在每次迭代中创建一个新数组。像这样(仅作为如何处理数组的示例):

function fillArray(value, len) {
  var arr = [];
  for (var i = 0; i < len; i++) {
    arr.push(value);
  }
  return arr;
}

19
最好在一开始就分配好所有的条目,通过arr = new Array(len);,然后在循环中通过索引为它们赋值,即arr[i] = value;。这样你只需要支付O(n)的成本,而不必在数组增长时不断重新分配数组。通常情况下,尽可能避免通过添加元素来增长数组是更好的选择。如果你知道最终大小,就使用它。 - Tom Karzes
73
将一个长度为5的数组创建出来,并将每个元素都赋值为2。 - noobninja
4
@noobninja:好的解决方案,你应该将其重新输入作为答案,这样它就可以得到赞同票。 - jsalvata
以下是后者的优化版本:function fillArray(value, len) { let n = new Array(len).fill(value); return n; } - undefined

52

如果您需要重复一个数组,请使用以下方法。

Array(3).fill(['a','b','c']).flat() 

会返回

Array(9) [ "a", "b", "c", "a", "b", "c", "a", "b", "c" ]

1
使用现有数组的绝妙一行代码,正是我所需要的。 - gneric
2
Array(3).fill(['a','b','c']).flat() - yongfa365
很好的回答。谢谢 @etoxin - Majid Sabzalian

47

Array.from({length:5}, i => 1) // [1, 1, 1, 1, 1]

或者创建一个值逐渐增加的数组

Array.from({length:5}, (e, i)=>i) // [0, 1, 2, 3, 4]


很好,如果您需要元素动态化,这是最佳方法。 - IliasT
Array.from({length:5}, i => 1) => i is is undefined since it represents empty value Array.from({length:5}, (e, i)=>i) => e is undefined since it represents empty value.It should be Array.from({length:5}, v => 1) and Array.from({length:5}, (v, i)=>i) - Rafal Enden

40

lodash 中,情况并不那么糟糕:

_.flatten(_.times(5, function () { return [2]; }));
// [2, 2, 2, 2, 2]

编辑: 更好的方法是:

_.times(5, _.constant(2));
// [2, 2, 2, 2, 2]

编辑:甚至更好:

_.fill(Array(5), 2);

3
_.times(length, _.constant(value)) - user1533401
1
从文档中: _.fill(Array(3), 2); 这离ES6不远了。 - kert

19

[c] * n 可以写成:

Array(n+1).join(1).split('').map(function(){return c;})

因此,对于[2] * 5而言。

Array(6).join(1).split('').map(function(){return 2;})

其实,Array(6).join(2).split('') 不是更简单吗?你为什么需要 map 函数呢? - Angela
5
返回 ["2", "2", "2", "2", "2"],而不是 [2, 2, 2, 2, 2]。 - brook hong

14

你也可以这样扩展数组的功能:

Array.prototype.fill = function(val){
    for (var i = 0; i < this.length; i++){
        this[i] = val;
    }
    return this;
};
// used like:
var arry = new Array(5)​.fill(2);
// or
var arry = new Array(5);
arry.fill(2);


​console.log(arry);​ //[2, 2, 2, 2, 2] 

我应该指出,扩展内置对象的功能可能会在您使用第三方库时导致问题。在做决定时,始终要权衡这一点。


不存在这样的“要求”。这只是在混合库时的最佳实践。 - Shmiddty
2
ES6中添加了一个填充方法。因此,我不建议将自己的东西添加到原型中,否则会覆盖更快且功能更强大的版本。 - Janus Troelsen
@Janus 你应该发布那个答案。 - JMM
1
为了避免覆盖JavaScript或第三方库,您可以在声明之前检查是否存在。 if(!Array.prototype.fill){} - Oliver
1
@JanusTroelsen 你所说的“真正的polyfill”是什么意思?我使用了一个polyfill。我的意思是:检查功能检测和实现,以防万一。 - Oliver
显示剩余3条评论

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