从给定数组生成增量值数组

Generate an array of incremental values from a given array

如何从给定数组生成增量值数组

我们的想法是创建一种菱形,阵列在到达阵列中间后开始缩小尺寸。换句话说,最长的数组将是包含数组中间值的数组或 (array.length/2 + 1)

如果元素短而无法在后半部分完成数组,只需将其替换为 'E' 以指示空 space,就像第二个示例一样。

example 1
var array = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p']
//the longest array in length is containing 'i' which is the value at 
    array.length/2 + 1
var output = [
    ['a'],
    ['b','c'],
    ['d','e','f'],
    ['g','h','i','j'], 
    ['k','l','m'],
    ['n','o'],
    ['p']
]

example 2
var array = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t']
enter code here
//the longest array in length is containing 'k' which is the value at array.length/2 + 1
var output = [
    ['a'],
    ['b','c'],
    ['d','e','f'],
    ['g','h','i','j'],
    ['k','l','m','n','o'],
    ['p','q','r','s'],
    ['t','E','E'],
    ['E','E'],
    ['E]
]

这是我试过的代码:

const values = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];
const halfLen = values.length/2 + 1;
var topArr = [];

for(let i = 0; i < values.length; i ++) {
    if(i <= halfLen) {
    topArr.push(values[i])
  }
    
}
console.log(topArr)

var filTopArr = [];

for(let i = 0; i <= topArr.length; i ++) {

    let prevIndex = i - 1;
    
    if(i === 0) {
        filTopArr.push(topArr[i])
    }  else if(i === 1) {
        filTopArr.push(topArr.slice(i, i + i + 1))
    } else {
    filTopArr.push(topArr.slice(i, i + i ))
    }
    
}

console.log(filTopArr)

我的想法是将数组分成两个不同的数组,这两个数组将成为大小递增的顶部部分和大小将减小的 second/bottom 部分。

上面的代码有这样的输出

[1, [2, 3], [3, 4], [4, 5, 6], [5, 6, 7, 8], [6, 7, 8, 9], [7, 8, 9], [8, 9], [9], []]

一些观察:

  • 输出中的字符串数(包括填充“E”字符串)始终是一个完美的平方(1、4、9、16、25 等)

  • 为了知道需要添加多少个“E”字符串,我们因此需要知道哪个是不小于输入大小的最不完美的平方。

  • 输出中最长(中间)的子数组的大小是该完美平方的平方根。

  • 子数组的个数是该数的两倍减1。

这导致以下实现:

function diamond(array) {
    // Get least perfect square that is not less than the array length 
    const sqrt = Math.ceil(Math.sqrt(array.length));
    const size = sqrt ** 2;
    // Pad the array with "E" strings so to reach that perfect square size
    const all = [...array, ..."E".repeat(size - array.length)];
    const length = 2 * sqrt;
    return Array.from({length}, (_, width) => {
        return all.splice(0, Math.min(width, length - width));
    }).slice(1); // Skip the first subarray that was produced (empty array)
}

// Demo using the two provided examples:
var array = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p'];
console.log(diamond(array));

var array = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t'];
console.log(diamond(array));

这是一个递归版本。请注意,display 仅用于演示目的。 唯一真正的工作是在 diamond:

const diamond = (xs, [len = xs.length, up = true, n = 1] = []) => n == 0 ? [] : [
  Object .assign (Array (n) .fill ('E'), xs .slice (0, n)),
  ...diamond (xs .slice (n), up && n * n < len  ? [len, true, n + 1] : [len, false, n - 1])
]

const display = (xss) => console .log (`${xss .map (
  (xs, i) => `${' '.repeat (Math .abs ((xss .length - 1) / 2 - i) + 1)}${xs .join (' ')
}`) .join ('\n')}`)


const demos = [
  ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p'],
  ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u'],
  [1, 2, 3, 4, 5, 6, 7, 8]
]


demos .forEach (array => display (diamond (array)))
.as-console-wrapper {max-height: 100% !important; top: 0}

我们跟踪当前字符串的长度(n,默认为1),原始数组的长度(len),以及一个布尔标志来判断是否我们的长度正在向上或向下移动 (up)。我们在初始迭代中增加 n,将输入中的下一个 n 个字符添加为下一个子数组。当 n 为零时,我们 return 一个空数组。当n ** n大于或等于len时,我们将up切换为false,然后从n开始减一。唯一需要做的就是用 'E' 填充我们剩余的数组。我们通过 Object .assign 调用来做到这一点。

如果您希望格式化输出更像数组文字形式,您可以使用此版本的 display:

const display = (xss) => console .log (`[\n${xss .map (
  (xs, i) => `${'  '.repeat (Math .abs ((xss .length - 1) / 2 - i) + 1)}['${xs .join (`','`)
}']`) .join ('\n')}\n]`)

得到这样的输出:

[
          ['a']
        ['b','c']
      ['d','e','f']
    ['g','h','i','j']
  ['k','l','m','n','o']
    ['p','q','r','s']
      ['t','u','E']
        ['E','E']
          ['E']
]

请注意,此递归有点霸道,具有三个独立的默认递归变量。我很可能会像这样使用 trincot 的解决方案。但是有替代品是很好的。