## Flatten an array Back

Flattening an array means to simplify an array with extracting embedded array of another array. The following case has apparently shown us what is flattening an array:

``````[[[1, 2], [1, 2, 3]], [1, 2]] => [1, 2, 1, 2, 3, 1, 2] /** flatten in a deep way */
[[[1, 2], [1, 2, 3]], [1, 2]] => [[1, 2], [1, 2, 3], 1, 2] /** flatten only one layer */
``````

Before analyzing the method `_.flatten()` of underscore, we will have a look at the predicate method `flatten()`:

``````var flatten = function(input, shallow, strict, startIndex) {
// ...
};
``````

As we can see above, the method has accepted four parameters, of which the `input` is the first one to get a given array. Then, `shallow` is a Boolean value for checking whether to flatten just one layer of the array. `startIndex` is used to set up where to start to flatten.

`strict` is also a Boolean value, but it's hard to understand. If `strict` is given a `true` value, then it means that each flattening will ignore any elements which is not an array. For example:

``````var ans = flatten([5, 6, [1, 2], [3, 4]], true, true);
console.log(ans); /** => [1, 2, 3, 4] */
``````

Therefore, if giving `false` to `shallow` and `true` to `strict` at the same time, the method should always return an empty array.

``````var flatten = function(input, shallow, strict, startIndex) {
/**
* ouput is the array to return
* idx is a counter
*/
var output = [], idx = 0;

/** start from a given startIndex or 0 by default */
for (var i = startIndex || 0, length = getLength(input); i < length; i++) {
var value = input[i];

/** if the value is an array of an argument, then flatten it */
if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
/**
* flatten current level of array or arguments object
* if `shallow` is false, then flatten recursively to reassign the value
*/
if (!shallow)
value = flatten(value, shallow, strict);

/** value shoule be an array */
var j = 0, len = value.length;

/** update the length? */
output.length += len;

/** push all elements of this value to the output array */
while (j < len) {
output[idx++] = value[j++];
}
} else if (!strict) {
/** if `strict` is false then do not ignore the element which is not an array */
output[idx++] = value;
}
}

return output;
};
``````

So `_.flatten()` has been completed by the following code snippet:

``````_.flatten = function(array, shallow) {
/** given array and whether to flatten just one layer */
return flatten(array, shallow, false);
};
``````

`_.union()` has also called `flatten()` to complete its duty to combine different sets (arrays with only unique elements):

``````_.union = function() {
return _.uniq(flatten(arguments, true, true));
};
``````

`_.difference()`, `_.pick()`, and `_.omit` have also used `flatten()` to implement. Therefore, one of the most elegant things of underscore is that it has created many predicate methods to implement hundreds of functions. 