创建具有相同元素多次重复的数组


323

在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;
};


Answers:


52

您可以这样做:

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;
}

11
预先分配所有条目arr = new Array(len);,然后使用,然后通过循环中的索引(即)分配给它们,效率更高arr[i] = value;。这样,您只需要支付O(n)即可,而不必在数组增长时继续重新分配数组。通常,最好尽可能通过附加来避免增长数组。如果您知道最终尺寸,请使用它。
汤姆·卡兹斯

26
Array.from({length:5}).map(x => 2)
noobninja

1
@noobninja:很好的解决方案;您应该重新输入它作为答案,以便对其进行投票。
jsalvata

692

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

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

3
Internet Explorer和Opera尚不支持。
DenisKolodin '16

4
Node.js <= 3不支持此功能。
Junle Li

1
@DenisKolodin当前的Opera会这么做。还有Edge。参见compat-table
Janus Troelsen'2

4
@Michael您可以使用Array(5).fill([1,2,3]).flat()。请注意,flat()仍处于试验阶段,浏览器支持很差。
Niko Ruotsalainen 18/09/16

3
请注意,参数to会fill被评估一次,因此Array(9).fill(someMutable)someMutable在数组中创建九个引用(将一个变量更改为“全部”)。
卡尔·史密斯,

146
>>> Array.apply(null, Array(10)).map(function(){return 5})
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
>>> //Or in ES6
>>> [...Array(10)].map((_, i) => 5)
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5]

6
愚蠢的问题,但是为什么新的Array(10).map不起作用?
blazkovicz 2015年

1
blazkovicz,请参阅zertosh对这个答案的评论,原因是这样。
罗斯·罗杰斯

5
使用ES6,可以将其“升级”到Array(...Array(10)).map(() => 5)传播操作员,也可以升级到Array.from(Array(10)).map(() => 5)
Christophe Vidal,2015年

4
根据MDN,您可以这样:Array.from({length: 10}, () => 5);
Plusb Preco 2015年

2
@blazkovicz Array(10)创建一个lenght = 10没有任何可枚举属性的数组。.map仅适用于可枚举的属性。该.apply方法获取此数组,并将其映射到一个arguments array(类似数组的对象)中,以传递给Array构造函数。arguments数组不能稀疏,因此缺少的属性将设置为undefined可枚举。现在我们可以按.map预期使用
CervEd

91

你可以试试:

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

更新(01/06/2018)

现在,您可以重复一组字符。

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

注意:有关兼容性和浏览器支持的更多信息,请参见fill(...)from(...)

更新(05/11/2019)

另一种方法,不使用fillfrom,可用于任何长度的字符串:

Array.apply(null, Array(3)).map(_ => 'abc') // ['abc', 'abc', 'abc']

与上述答案相同。为了完整性而添加。


1
真好 最简单快捷。
Johann Echavarria 2014年

2
+1为简单处理。可惜您不能从中创建空字符串数组。除了那个非常聪明的人...
更快2014年

1
Array(6).join('a')。split('a')给我一个空字符串数组。
Vivek

17
这仅适用于1个char字符串,因此无法完全回答问题。
az_

3
@AlfonsoVergara:在Java语言中,String是一种原始(值语义)类型;无法获得两个字符串来引用相同的数据(因为字符串不是 Javascript中的引用;它们是值)。您确实需要注意对象和列表的引用语义,而不是字符串。
Quuxplusone

36

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)=> iundefined因为它代表空值Array.from({length:5}, (e, i)=>i)=> eundefined因为它代表空值。它应该是Array.from({length:5}, v => 1)Array.from({length:5}, (v, i)=>i)
拉法尔Enden

33

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 2014年

1
来自文档:_.fill(Array(3),2); 这是不远处ES6
KERT

15

[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('')会不会更容易?为什么需要地图?
安吉拉2014年

4
返回[“ 2”,“ 2”,“ 2”,“ 2”,“ 2”],而不是[2、2、2、2、2]。
布鲁克洪2014年

10

您还可以像这样扩展Array的功能:

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] 

我应该注意,如果您使用第三方库,则扩展内置对象的功能可能会导致问题。始终将其纳入您的决策中。


请注意,如果将一个对象传递fill给数组中的每个索引,都将引用同一对象,因此更改一个将更改所有对象。如果成为问题,这并不是很难解决。
Shmiddty 2012年

我不明白为什么许多javascript用户都不知道不对本机函数进行原型设计的要求。
brooNo

2
一个填充方法已在ES6被添加。因此,我不建议您将自己的东西添加到原型中,否则您将覆盖速度更快,功能更强大的版本。
Janus Troelsen

1
@JanusTroelsen为避免覆盖JavaScript或第三方库,您可以在声明之前检查是否存在。if (!Array.prototype.fill) { }
奥利弗(Oliver)

1
@JanusTroelsen“真正的填充”是什么意思?我使用了polifyll。我的意思是:如果没有,请检查功能检测和实现。
奥利弗(Oliver)2013年



4

没有更简单的方法。您需要进行循环并将元素推入数组。


谢谢!在我接受之前,在效率方面是push更好还是concat更好?
Curious2learn 2012年

CONCAT需要检查两个数组,PUSH只是添加了另一个元素,因此我希望PUSH通常更有效,但是对于IDENTICAL DATA,我认为Guffa的答案很明确。
Diodeus-James MacFarlane 2012年

无需循环,请参阅我的答案。
Janus Troelsen

@JanusTroelsen,除非您需要一种有效的方法来执行此操作,否则无需循环。您的发现是您发现的较慢的实现之一。push()到[]是最快的。
chrilith 2015年

4

使用此功能:

function repeatElement(element, count) {
    return Array(count).fill(element)
}
>>> repeatElement('#', 5).join('')
"#####"

或更紧凑的版本:

const repeatElement = (element, count) =>
    Array(count).fill(element)
>>> repeatElement('#', 5).join('')
"#####"

或针对可咖喱的版本:

const repeatElement = element => count =>
    Array(count).fill(element)
>>> repeatElement('#')(5).join('')
"#####"

您可以将此功能与列表一起使用:

const repeatElement = (element, count) =>
    Array(count).fill(element)

>>> ['a', 'b', ...repeatElement('c', 5)]
['a', 'b', 'c', 'c', 'c', 'c', 'c']

4

如果需要重复一个数组,请使用以下内容。

Array.from({ length: 3 }).fill(['a','b','c']).flat()

将返回

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

伟大的oneliner使用现有的阵列,我需要的是。
gneric


1

该函数创建一个(长度)元素数组,其中每个元素等于(值),只要(值)是整数或整数字符串即可。任何十进制数字将被截断。如果您确实想要十进制数字,请用“ parseFloat( ” 替换“ parseInt

function fillArray(length, intValue) {
     var vals = (new Array(length + 1)).join(intValue + '|').split('|').slice(0,length);
     for(var i = 0; i < length; i += 1) {
         vals[i] = parseInt(vals[i]);
     }
     return vals;
}

例子:

fillArray(5, 7) // returns [7,7,7,7,7]
fillArray(5, 7.5) // returns [7,7,7,7,7]
fillArray(5, 200) // returns [200,200,200,200,200]

1

我在使用类似数组时遇到上述方法的问题

var array = ['foo', 'bar', 'foobar'];
var filled = array.fill(7);

//filled should be ['foo', 'bar', 'foobar', 'foo', 'bar', 'foobar', 'foo']

为此,我正在使用:

Array.prototype.fill = function(val){
    var l = this.length;
    if(l < val){
        for(var i = val-1-l; i >= 0; i--){
            this[i+l] = this[i % l];
        }
    }
    return this;
};

很好,但是应该命名为cycle
德伦米2015年

1

我今天在尝试不使用循环而制作2D阵列时发现了这一点。回想起来,加入一个新的数组很整齐。我尝试映射新数组,但由于map跳过了空插槽,因此无法正常工作。

"#".repeat(5).split('').map(x => 0)

“#”字符可以是任何有效的单个字符。5将是所需元素数量的变量。7是您要用来填充数组的值。

新的填充方法更好,当我对此进行编码时,我不知道它的存在,也不知道重复的是es6。我将写一篇博客文章,介绍如何结合使用此技巧和reduce来做一些有趣的事情。

http://jburger.us.to/2016/07/14/functionally-create-a-2d-array/





0

也可以用作单线:

function repeat(arr, len) {
    while (arr.length < len) arr = arr.concat(arr.slice(0, len-arr.length));
    return arr;
}

0

改进Vivek的答案,这适用于任何长度的字符串,以填充长度为n的数组:Array(n+1).join('[string to be repeated][separator]').split('[separator]').slice(0, n)


-1

我需要一种方法来重复/循环一个数组(包含n个项)m次。

例如,将(人员)列表分发到一周/一个月。假设我有3个名字,我希望它们在一周内重复出现:

fillArray(["Adam", "Blair", "Curtis"], 7); // returns ["Adam", "Blair", "Curtis", "Adam", "Blair", "Curtis", "Adam"]

function fillArray(pattern, count) {
    let result = [];
    if (["number", "string"].includes(typeof pattern)) {
        result = new Array(5);
        result.fill(pattern);
    }
    else if (pattern instanceof Array) {
        for (let i = 0; i < count; i++) {
            result = result.concat(pattern);
        }
        result = result.slice(0, count);
    }
    return result;
}

fillArray("a", 5);        // ["a", "a", "a", "a", "a"]
fillArray(1, 5);          // [1, 1, 1, 1, 1]
fillArray(["a", "b"], 5); // ["a", "b", "a", "b", "a"]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.