Javascript - 有没有更有效的方法来创建数组? - 提供的例子

Posted

技术标签:

【中文标题】Javascript - 有没有更有效的方法来创建数组? - 提供的例子【英文标题】:Javascript - Is there a more efficient way to create an array of arrays? - Examples provided 【发布时间】:2018-07-15 05:54:49 【问题描述】:

问题:有没有更有效的方法来创建由递增数字组成的数组?

我创建了一个函数来生成一个递增数字数组的数组,这比预期花费的时间要长得多,我确信有一种更有效的方法可以实现这一点(我是 JS 新手)。

示例 1 和 2 的 genArray 函数的注意事项: argu1 声明数字范围的开始(例如 0 = 从 0 开始), argu2 声明数字范围的结束(例如 9 = 以 9 结束), argu3 声明每个单独的数组中需要多少个数字(例如 3 = 在数组中生成 3 个数字), argu4 携带临时数组生成单个数字数组, argu5通过函数和嵌套函数携带数组数组。

示例 1:下面是纯粹用于创建递增数字数组的代码。我的问题是指制作这个函数的更高效版本。

function genArray(start, finish, quantity, array, allArray = []) 
  var collectArray = allArray;

  //Cycle through digits from start to finish, e.g. 0-9
  for (var i = start; i <= finish; i++) 
    var tempArray = [];

    //Collect digits for a single array if not first iteration
    if (array !== undefined) 
      tempArray = tempArray.concat(array);
    ;

    //Add digit to single level array
    tempArray.push(i);

    //If not highest level, go higher
    if (quantity > 1) 
      var genArray2 = genArray(start, finish, quantity-1, tempArray, collectArray);
     

    //If highest level collect a single array
    else if (quantity == 1) 
      collectArray.push(tempArray);
    
  
  return collectArray;


//Call function with arguments
//argu1 declares the start of the number range, argu2 declares the end of the number range, argu3 declares how many numbers are needed in each individual array, argu4 carrays the temp array to generate a single array of numbers, argu4 carrys the array of arrays throught the function and nested functions. 
var genArray2 = genArray(0, 9, 3);
console.log(genArray2);

这会产生这样的日志:

[ [ 0, 0, 0 ],
  [ 0, 0, 1 ],
  [ 0, 0, 2 ],
  [ 0, 0, 3 ],
  [ 0, 0, 4 ],
  [ 0, 0, 5 ],
  [ 0, 0, 6 ],
  [ 0, 0, 7 ],
  [ 0, 0, 8 ],
  [ 0, 0, 9 ],
  [ 0, 1, 0 ],
  [ 0, 1, 1 ],
  [ 0, 1, 2 ],
  [ 0, 1, 3 ],
  [ 0, 1, 4 ],
  [ 0, 1, 5 ],
  [ 0, 1, 6 ],
  [ 0, 1, 7 ],
  [ 0, 1, 8 ],
  [ 0, 1, 9 ],
  [ 0, 2, 0 ],
  [ 0, 2, 1 ],
  [ 0, 2, 2 ],
  [ 0, 2, 3 ],
  [ 0, 2, 4 ],
  [ 0, 2, 5 ],
  [ 0, 2, 6 ],
  [ 0, 2, 7 ],
  [ 0, 2, 8 ],
  [ 0, 2, 9 ],
  [ 0, 3, 0 ],
  [ 0, 3, 1 ],
  [ 0, 3, 2 ],
  [ 0, 3, 3 ],
  [ 0, 3, 4 ],
  .... up to [ 9, 9, 9 ]

示例 2:下面是我实际使用的代码,唯一的变化是添加了一个检查以查看生成的数组是否是升序的,并且每个数字都是唯一的,并且只存储在这两种情况下都是正确的。提供这个作为上下文,以防它对某人有用:

//Check if ascending
function ascending(x) 
  return x == parseInt(x.toString().split('').sort().join(''));


//Check if unique
function unique(x) 
  return x.toString().split('').length == [...new Set(x)].length


//Create an array of arrays of ascending and unique numbers    
function genArray(start, finish, quantity, array, allArray = []) 
  var collectArray = allArray;

  //Cycle through digits from start to finish, e.g. 0-9
  for (var i = start; i <= finish; i++) 
    var tempArray = [];

    //Collect digits for a single array if not first iteration
    if (array !== undefined) 
      tempArray = tempArray.concat(array);
    ;

    //Add digit to single level array
    tempArray.push(i);

    //If not highest level, go higher
    if (quantity > 1) 
      var genArray2 = genArray(start, finish, quantity-1, tempArray, collectArray);
     

    //If highest level collect a single array
    else if (quantity == 1 && ascending(tempArray.join('')) && unique(tempArray.join(''))) 
      collectArray.push(tempArray);
    
  
  return collectArray;


//Call function with arguments
var genArray2 = genArray(0, 9, 3);
console.log(genArray2);

这会产生这样的日志:

[ [ 0, 1, 2 ],
  [ 0, 1, 3 ],
  [ 0, 1, 4 ],
  [ 0, 1, 5 ],
  [ 0, 1, 6 ],
  [ 0, 1, 7 ],
  [ 0, 1, 8 ],
  [ 0, 1, 9 ],
  [ 0, 2, 3 ],
  [ 0, 2, 4 ],
  [ 0, 2, 5 ],
  [ 0, 2, 6 ],
  [ 0, 2, 7 ],
  [ 0, 2, 8 ],
  [ 0, 2, 9 ],
  [ 0, 3, 4 ],
  [ 0, 3, 5 ],
  [ 0, 3, 6 ],
  [ 0, 3, 7 ],
  [ 0, 3, 8 ],
  [ 0, 3, 9 ],
  [ 0, 4, 5 ],
  [ 0, 4, 6 ],
  [ 0, 4, 7 ],
  [ 0, 4, 8 ],
  [ 0, 4, 9 ],
  [ 0, 5, 6 ],
  [ 0, 5, 7 ],
  [ 0, 5, 8 ],
  [ 0, 5, 9 ],
  [ 0, 6, 7 ],
  [ 0, 6, 8 ],
  [ 0, 6, 9 ],
  [ 0, 7, 8 ],
  [ 0, 7, 9 ],
  [ 0, 8, 9 ],
  [ 1, 2, 3 ],
  [ 1, 2, 4 ],
  [ 1, 2, 5 ],
  [ 1, 2, 6 ],
  .... up to [ 7, 8, 9 ]

【问题讨论】:

您的代码有效 - 您究竟在寻找什么样的改进? (可能比这里更适合代码审查) 嗨@CertainPerformance,是否已经有实现此目的的函数/方法或函数/方法的组合?另外,codereview,这是 Stack 上的一个部分吗? 【参考方案1】:

没有递归,您将能够加快它的速度。这是一个循环,它只使用先前添加的子数组来计算下一个。它使用将 1 添加到十进制数时的机制:首先增加最右边的数字。如果超出范围(十进制:变为 10),则将其设置回最低位并增加其左侧的数字,...等等,直到最后更改的数字保持在范围内:

function genArray(start, finish, quantity) 
    const current = Array(quantity).fill(start);
    const result = [];
    for (let i = quantity; i >= 0; null) 
        result.push(current.slice());
        for (i = quantity; i--; null) 
            current[i]++;
            if (current[i] <= finish) break; 
            current[i] = start;
        
    
    return result;


console.log(genArray(0, 2, 3));

【讨论】:

这个循环不是“直截了当”,而是充满曲折的段落,都一样 @Tibrogargan,我删除了直截了当这个词并添加了更多解释。你认为这足够清楚吗? 是的,我相信是的。这是一段令人愉快的代码,但如果没有解释,新手可能很难破译。 谢谢@trincot!它保留所有功能,允许“完成”超过 9,并指定数量。干净且易于阅读。还向我介绍了新方法以及代码在没有递归的情况下可能更高效的想法。 :)【参考方案2】:

如果您愿意做一些数学运算,一般来说,有一种非常快速简单的方法可以做到这一点。基本的见解是,像768 这样的数字可以分解为以 10 为模的各种 log10 组件。例如,Math.floor(768/100) % 10 为您提供第三位数字。 Math.floor(768/10) % 10 给你第二个。要获得您需要的内部数组的长度,您可以使用Math.floor(Math.log10(largestNumber + 1))。所以对于1000,这将是4,对于999,它将是3,等等。这种排列中唯一令人讨厌的部分是数组是从左到右构建的,而数字是从右到左构建的。这就是我们使用长度 - 内部数组中的索引的原因。

你可以把它和Array.from放在一起做一个简洁的函数,避免大量的字符串解析和if/else子句:

function genArray(start, finish) 
  return Array.from(length: finish - start + 1, (_, i) => 
    let ind = i + start
    let innerLength = Math.floor(Math.log10(finish + 1))
    return Array.from(length: innerLength + 1, (_, i) => Math.floor(ind / (10 ** (innerLength - i))) % 10)
  )


let a = genArray(0, 20)
console.log(a.join(' · '))

a = genArray(1020, 1040)
console.log(a.join(' · '))

此外,尚不清楚您的数组将有多大,但如果您正在处理大量数字,则制作生成器可能会提高内存效率,因此您只需根据需要生成内部数组。这不是所有事情的正确解决方案,但由于它几乎是相同的代码,我想我会提到它:

function* genArray(start, finish) 
  let innerLength = Math.floor(Math.log10(finish + 1))
  while (start <= finish) 
    yield Array.from(length: innerLength + 1, (_, i) => Math.floor(start / (10 ** (innerLength - i))) % 10)
    start++
  

let a = genArray(101, 105)
console.log(a.next().value)

let b = genArray(20, 30)
console.log([...b].join(' · '))

【讨论】:

【参考方案3】:

这是一个可能的解决方案:

function genArrays(start, end)
    let max_len = String(end).length;
    let arr = [];
    let cur_num = start;
    let arr_num;

    for (let i = start; i <= end; i++)
        str_num = String(cur_num).padStart(max_len, '0').split('').map(x => parseInt(x));

        arr.push(str_num);

        cur_num++;
    
    
    return arr;


console.log(genArrays(0, 1000));
console.log(genArrays(102, 1043));

核心在这里:str_num = String(cur_num).padStart(max_len, '0');。首先将一个计数器串起来,然后在左侧应用一个填充,以达到串 end 的长度。

【讨论】:

不考虑原文的所有论点【参考方案4】:

我的英语不太好,希望能理解你的问题。

从您提供的示例来看,您似乎只需要一个 2 级数组,第一个包含 n 个递增数字数组。

您可以尝试使用普通的for循环,而不是使用占用大量内存的递归函数,并对每个数字进行拆分,用0填充以获得n长度..不知道是否可以为你工作。

0002.split 创建数组[0,0,0,2].. 然后推到主数组上

应该是最快的方式

//s start, e end, n array size
f=new Array();
a=new Array();
for (i=s; i<e; i++) 
 t=pad(i,n);
 a=i.toString().split('');
 f[f.length]=a;


function pad(s,n)  
   while (s.length < n) 
      s = '0' + s; 
   return s; 
;

干杯 丹尼尔

【讨论】:

您的pad 可以替换为String.padStart。也许你可以声明你的变量。

以上是关于Javascript - 有没有更有效的方法来创建数组? - 提供的例子的主要内容,如果未能解决你的问题,请参考以下文章

javascript中的IndexOf方法比遍历数组更有效吗?

使用犰狳访问下三角元素的更有效方法

有没有更有效的方法来编写 $('parent > child')?

有没有更有效的方法来计算减法表达式的绝对值

有没有更有效的方法来执行这个嵌套的 SQL 查询?

有没有更有效的方法来码头化 Luarocks?