1

How to generate an array of incremental values from a given array

the idea is to create a kind of diamond shape where the arrays start decreasing in size once they reach the middle of the array. In other words the longest array is going to be the one that is containing the middle value of the array or (array.length/2 + 1)

and in cases where the elements are short to complete the array on the second half just replace it with 'E' to indicate empty space just like on the second example.

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]
]

Here is the code i have tried:

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)

my idea here was to separate the array into two different arrays which are going to be the top part that is incrementing in size and the second/bottom part that is going to be decreasing in size.

The above code had this output

[1, [2, 3], [3, 4], [4, 5, 6], [5, 6, 7, 8], [6, 7, 8, 9], [7, 8, 9], [8, 9], [9], []]
4
  • Note: Those aren't diamonds, they're triangles. A 2D diamond (more accurately, rhombus) has four sides, not three. Commented Mar 23, 2022 at 11:52
  • @T.J.Crowder: But it's easy enough to see these as rhombi, simply by centering each row. Commented Mar 23, 2022 at 13:48
  • @ScottSauyet - Sure (easier in a fixed-font environment if you increase by two each time), but as shown, they're triangles. Commented Mar 23, 2022 at 13:49
  • @T.J.Crowder: They're actually ragged multi-dimensional arrays, and any connection to planar geometry requires some squinting. When I've given similar exercises to students, I ask for a rhombus-styled output (really squares at 45°.) I think either interpretation is reasonable. Commented Mar 23, 2022 at 13:55

2 Answers 2

5

Some observations:

  • The number of strings in the output (including the padding "E" strings) is always a perfect square (1, 4, 9, 16, 25, ...etc)

  • In order to know how many "E" strings need to be added, we thus need to know which is the least perfect square that is not less than the input size.

  • The longest (middle) subarray in the output has a size that is the square root of that perfect square.

  • The number of subarrays is the double of that number minus 1.

This leads to the following implementation:

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

Sign up to request clarification or add additional context in comments.

1 Comment

And it's a triangle, not a diamond as the OP called it. :-)
2

Here's a recursive version. Note that display is just for presentation purposes. The only real work is in 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}

We track the length of the current string (n, defaulting to 1), the length of the original array (len) , and a boolean flag to tell whether our length is moving up or down (up). We increase n on initial iterations, adding the next n characters from our input as the next subarray. When n hits zero we return an empty array. When n ** n is greater than or equal to len, we switch up to false and start subtracting one from n from then on. The only other necessity is to fill our remaining array with 'E's. We do this with an Object .assign call.

If you want formatted output more like an array literal form, you could use this version of 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]`)

to get output like this:

[
          ['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']
]

Note though that this recursion is a little overbearing, with three separate defaulted recursive variables. I would be as likely to go with trincot's solution as this. But it's good to have alternatives.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.