5
\$\begingroup\$

I'm currently trying to teach myself JavaScript. If someone could critique my implementation of Pascal's Triangle I would be very grateful.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Pascal's Triangle</title>
        <style>
            .container {
                display: block;
            }

            .row {
                text-align: center;
            }

            .cell {
                border: 1px solid black;
                border-width: 1px 0px 0px 1px;
                display: inline-block;
                width: 40px;
                padding: 10px 0px;
            }

            .row .cell:last-child {
                border-right-width: 1px;
            }

            .container .row:last-child .cell {
                border-bottom-width: 1px;
            }
        </style>
    </head>
    <body>
        <div id="container" class="container"></div>
        <script>
            var rows = 10;
            var pascalsTriangle = [];
            for (var i = 0; i < rows; i++) {
                pascalsTriangle.push([]);
                for (var j = 0; j < rows; j++) {
                    pascalsTriangle[i].push(0);
                }
            }

            pascalsTriangle[0][0] = 1;
            var upperLeft, upper = null;
            for (var y = 1; y < rows; y++) {
                for (var z = 0; z < rows; z++) {
                    upperLeft = pascalsTriangle[y - 1][z - 1] === undefined ? 0 : pascalsTriangle[y - 1][z - 1];
                    upper = pascalsTriangle[y - 1][z];
                    pascalsTriangle[y][z] = upperLeft + upper;
                }
            }

            var html = "";
            for (var a = 0; a < rows; a++) {
                html += '<div class="row">';
                for (var b = 0; b < rows; b++) {
                    if (pascalsTriangle[a][b] === 0) {
                        continue;
                    }
                    html += '<div class="cell">' + pascalsTriangle[a][b] + "</div>";
                }
                html += "</div>";
            }
            document.getElementById("container").innerHTML += html;
        </script>
    </body>
</html>

My code is also hosted on JSFiddle if anyone wants to see it in action.

\$\endgroup\$
1
\$\begingroup\$

I see your code is split into 3 phases: Initializing the triangle, calculating the values and then rendering the HTML. You can actually skip the first phase, and create the triangle on-the-fly, as you calculate.

The last phase we can eliminate one loop (the one that loops through cells) by using some array trickery. Since we're just constructing a string, we can use an array's join method to put markup between array elements. Then we prepend and append the missing markup of the resulting string.

Also, I think you should improve on your variable names. a, b, i, j, y and z don't really mean anything. They're "assumend" to be for iteration purposes. However, someone might see y and z as axes in a graph or something, which may be confusing.

And I think it's easier if you calculate the triangle by assuming that the row will always start with a 1. That way, the second item in the current row (essentially the first one we're actually calculating) is in line with the first item of the previous row. That way, summing is a matter of getting the value of the previous row at the same index, and the one to its right. At the end of the row, the "right" value will be undefined (accessing an out of bounds index) which you can easily replace with a 0.

        1
      1 1
    1 2 1
  1 3 3 1
1 4 9 4 1

With that, here's my take on it:

var rows = 10;

function range(n) {
  return Array.apply(null, Array(n)).map(function(_, i) { return i; });
}

// I use range to create a zero-indexed array of things to iterate.
// It's an alternative to using loops.
var pascalsTriangle = range(rows - 1).reduce(function(carry, index) {
  // Using the previous row, we calculate the next row and add to the tree
  carry.push(carry[index].reduce(function(carry, left, index, previousRow) {
    // Determine the "right"
    carry.push(left + (previousRow[index + 1] || 0));
    return carry;
  // Assume the row always starts with 1
  }, [1]));
  return carry;
// Our initial 1
}, [[1]]);

var html = pascalsTriangle.map(function(row) {
  // Instead of looping through a second time, I use `.join` to fill
  // the markup between. Then prepend and append the missing markup.
  return '<div class="row"><div class="cell">' + row.join('</div><div class="cell">') + '</div></div>';
}).join('');

document.getElementById("container").innerHTML += html;
.container {
  display: block;
}
.row {
  text-align: center;
}
.cell {
  border: 1px solid black;
  border-width: 1px 0px 0px 1px;
  display: inline-block;
  width: 40px;
  padding: 10px 0px;
}
.row .cell:last-child {
  border-right-width: 1px;
}
.container .row:last-child .cell {
  border-bottom-width: 1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>
<div id="container" class="container"></div>

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Brilliant, thank you very much :) I will try again incorporating your points into my work this time. Much appreciated :) \$\endgroup\$ – user89506 Nov 16 '15 at 9:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy