1

I have a stepped array of elements that is filled as follows:

class Funnel{
    constructor() {
        this.funnelContents = [];
        this.layer = 0;
    }
    
    get content() {
        return this.funnelContents;
    }

    fill(...nums) {
        let index, startIndex = 0;
        for(let i = 0; i < this.funnelContents.length; i++){
            while ((index = this.funnelContents[i].indexOf(' ', startIndex)) > -1 && nums.length > 0) {
                    this.funnelContents[i][index] = nums.shift();
                    startIndex = index + 1;
            }
        }
        return nums
            .splice(0, 15 - this.funnelContents.reduce((count, row) => count + row.length, 0))
            .filter(num => num < 10)
            .reduce((arr, num) => {
                if (this.funnelContents.length) {
                    this.funnelContents[this.funnelContents.length - 1] = this.funnelContents[this.funnelContents.length - 1].filter(char => char !== ' ');
                    if ((this.funnelContents[this.layer] || []).length !== this.funnelContents[this.layer - 1].length + 1) {
                        this.funnelContents[this.layer] = [...(this.funnelContents[this.layer] || []), num];
                    } else {
                        this.layer++;
                        this.funnelContents[this.layer] = [num];
                    }
                }
                else {
                    this.layer++;
                    this.funnelContents = [...this.funnelContents, [num]];
                }
            }, []);

    }

    toString() {
        let str = '', nums = '', spacesCount = 1;
        for(let i = 5; i > 0; i--){
            str += '\\';
            for(let j = 0; j < i; j++) {
                if (this.funnelContents[i - 1] !== undefined) {
                    if (this.funnelContents[i - 1][j] !== undefined) {
                        nums += this.funnelContents[i - 1][j];
                    } else {
                        nums += ' ';
                    }
                } else {
                    nums += ' ';
                }
            }
            str += nums.split('').join(' ') + '\/\n' + ' '.repeat(spacesCount);
            nums = '';
            spacesCount++;
        }
        return str.substring(0, str.length - 6);
    }
}

let funnel1 = new Funnel();
let funnel2 = new Funnel();
let funnel3 = new Funnel();
let funnel4 = new Funnel();
let funnel5 = new Funnel();
let funnel6 = new Funnel();
let funnel7 = new Funnel();

funnel1.fill(5,4,3,4,5,6,7,8,9,3,2,4,5,6,7,5,6,7,8); //15 elements will be added, the rest are ignored

funnel2.fill(5,4,3,4,5,6,7,8);
funnel2.fill(9,3,2,4,5,6,7);

funnel3.fill(' ');
funnel3.fill(1,5,7);

funnel4.fill(1,2,3);
funnel4.fill(' ');
funnel4.fill(3,4,5);

funnel5.fill(1);
funnel5.fill(' ', ' ', ' ');
funnel5.fill(8,2,1);

funnel6.fill(' ',' ');
funnel6.fill(1,8,2,1);

funnel7.fill(' ',' ',' ',' ',' ');
funnel7.fill(1,8,2,1);

console.log(funnel1.toString()); // the output is as expected.
console.log(funnel2.toString()); // the same result
console.log(funnel3.toString()); // expected [ [1], [5,7] ] and it really is
console.log(funnel4.toString()); // expected [ [1], [2,3], [3,4,5] ] and it really is
console.log(funnel5.toString()); // expected [ [1], [8,2], [1] ] and it really is
console.log(funnel6.toString()); // expected [ [1], [8,2], [1] ] but got [ [], [1,8], [2], [1] ]
console.log(funnel7.toString()); // nothing is changed

Here you can see that at the very beginning of the function fill a cycle was written to insert elements that came to the input instead of spaces. I added spaces artificially, in fact, there is another function that adds them. But:

1) For some reason this does not always work, for an array in the example it does not work. With a simpler space search algorithm, it also does not work properly:

for (let i = 0; i < this.funnelContents.length; i++) {
      for (let j = 0; j < this.funnelContents[i].length; j++) {
        if(this.funnelContents[i][j] === ' '){
            this.funnelContents[i][j] = nums.shift();
        }
    }
}

2) It looks very cumbersome and I would like to do something similar more elegantly. I was thinking of two for loops to find elements I need, but I still hope that I can implement insertion instead of spaces inside reduce function.

Nikita Kobtsev
  • 151
  • 2
  • 8
  • 3
    do you have some explanation what the code is supposed to do (if it works)? with some examples possibly? – Nina Scholz Aug 06 '19 at 13:26
  • 2
    You have created an excellent working snippet. But, that's only a part of creating a good [mcve]. Please explain what his code is supposed to do and add some sample inputs & the expected output. – adiga Aug 06 '19 at 13:30
  • 1
    Please add a sample and the expected result, this is a very interesting question. – briosheje Aug 06 '19 at 13:45
  • It mayn't be noticeable, but in the last line of code there is a comment with the desired result. It was there originally – Nikita Kobtsev Aug 06 '19 at 13:53
  • yes, there is a result for four values. but what should happen for less or more values? what is the first call of `fill` doing? – Nina Scholz Aug 06 '19 at 13:56
  • @NikitaKobtsev there is no explanation about **why** it should be like that, though. Please, add further informations. – briosheje Aug 06 '19 at 14:01
  • The post has been updated – Nikita Kobtsev Aug 06 '19 at 14:25
  • I can also provide code for the entire program, along with a convenient display of the contents of the array and the delete function itself (perhaps the problem will become more obvious). But the contents of a piece of code will triple – Nikita Kobtsev Aug 06 '19 at 14:30
  • please add what the first `fill` is doing. does it implement a pattern for the next numbers? where is in `funnel4` the last one coming from? – Nina Scholz Aug 06 '19 at 14:31
  • may I suggest changing your log messages to `console.log(JSON.stringify( /*...*/ ))` so that the arrays are all on one line like your comments? It would be more clear than than your `funnel.toString()`, I think, because it matches your claim in the comment. – Wyck Aug 06 '19 at 14:40
  • @NinaScholz I'm not sure if this is a design pattern, but I added a draw function to make the task clearer – Nikita Kobtsev Aug 06 '19 at 14:43
  • @Wyck I forget that it depends on the execution environment. I have single line output by default. Instead, I added `toString` function to the code, now it's all more obvious – Nikita Kobtsev Aug 06 '19 at 14:44
  • I think the problem is directly related to spaces, but I don't know the solution. see https://stackoverflow.com/questions/35476948/remove-empty-or-whitespace-strings-from-array-javascript – jeffld Aug 06 '19 at 14:56
  • @jeffld `.trim` method and work with regular expressions is apparently string handling. And it really is! I don’t handle the strings inside the `fill` function – Nikita Kobtsev Aug 06 '19 at 15:09

1 Answers1

1

You could take a single loop and slice substrings with increasing length.

function funnel(array) {
    var i = 0,
        l = 0,
        result = [];

    while (i < array.length) result.push(array.slice(i, i += ++l));
    return JSON.stringify(result);
}
console.log(funnel([1]));
console.log(funnel([1, 2]));
console.log(funnel([1, 2, 3]));
console.log(funnel([1, 2, 3, 4]));
console.log(funnel([1, 2, 3, 4, 5]));
console.log(funnel([1, 2, 3, 4, 5, 6]));
console.log(funnel([1, 2, 3, 4, 5, 6, 7]));
console.log(funnel([1, 2, 3, 4, 5, 6, 7, 8]));
console.log(funnel([1, 2, 3, 4, 5, 6, 7, 8, 9]));
console.log(funnel([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]));
console.log(funnel([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]));
console.log(funnel([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]));
console.log(funnel([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]));
console.log(funnel([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]));
console.log(funnel([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]));
.as-console-wrapper { max-height: 100% !important; top: 0; }

As I understand the comment, you have an array in the given style with incrementing count, but some elements are spaces and this elemenst should bereplaced with the given data.

In this case, a nested loop for getting the result set right and another index for getting the value from the data array should work.

class Funnel {
    constructor() {
        this.funnelContents = [];
    }

    get content() {
        return this.funnelContents;
    }

    fill(...nums) {
        var i = 0,
            j = 0,
            l = 1,
            k = 0,
            target = this.funnelContents;
        
        while (k < nums.length) {
            if (!target[i]) target.push([]);
            if ([undefined, ' '].includes(target[i][j])) target[i][j] = nums[k++];
            if (++j === l) {
                if (++i > 4) break; // max 15 elements in result set
                j = 0;
                l++;
            }
        }
    }
}

var funnel = new Funnel;

funnel.fill(' ', ' ', ' ', ' ');
console.log(JSON.stringify(funnel.content));

funnel.fill(1, 2, 3, 4, 5, 6, 7, 8, 9);
console.log(JSON.stringify(funnel.content));

funnel.fill(10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
console.log(JSON.stringify(funnel.content));
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • 1
    May I offer advice here for readability of the output: Make an output function `out = (x) => console.log(JSON.stringify(x))` to get the output on a single line. – Wyck Aug 06 '19 at 14:45
  • @Wyck, great idea! – Nina Scholz Aug 06 '19 at 14:45
  • 1
    Wow, I haven’t noticed this solution before. But the snag is somewhat different. The array may contain spaces. When adding new elements, spaces should be replaced by them. I have already reconciled with the fact that inside the cycle for adding elements it's impossible to fit the check and somehow it'll be a different cycle. I was originally interested in the solution to add and at the same time replace the spaces with new elements. Thank you so much for this elegant solution! – Nikita Kobtsev Aug 06 '19 at 15:01
  • Updated post again. Added one more example (No. 2), from which it becomes clear that your first solution will not work for my task. I apologize for forgetting to cover this condition with examples. **P.S. While editing the post and writing this comment, you updated your post. Thank you!** – Nikita Kobtsev Aug 06 '19 at 17:40
  • Once again, I apologize, but forgot to indicate that the total size of the arrays cannot exceed 15. How can I control this? In my code, I did this as follows: `nums.splice(0, 15 - this.funnelContents.reduce((count, row) => count + row.length, 0))` – Nikita Kobtsev Aug 06 '19 at 17:54