2

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

我创建了一个函数来生成一个递增数字数组的数组,这比预期的要长得多,我相信有一种更有效的方法可以实现这一点(我是 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 ]
4

4 回答 4

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(' · '))

于 2018-07-15T06:29:49.683 回答
2

如果没有递归,您将能够加快速度。这是一个循环,它只使用先前添加的子数组来计算下一个。它使用将 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));

于 2018-07-15T07:14:11.527 回答
1

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

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

于 2018-07-15T06:43:50.280 回答
0

我不会说一口流利的英语,我希望能理解你的问题。

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

除了使用占用大量内存的递归函数之外,您还可以尝试使用正常的 for 循环,并对每个数字进行拆分,用 0 填充以获得 n 长度。不知道它是否适合您.

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

应该是最快的方法

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

干杯丹尼尔

于 2018-07-15T06:35:29.223 回答