JavaScript data flattening detailed explanation

JavaScript data flattening detailed explanation

What is Flattening

Flattening an array is to convert a nested array (nesting can be any number of layers) into an array with only one layer.

For example, suppose there is a function called flatten that can flatten an array. The effect will be as follows:

var arr = [1, [2, [3, 4]]];
console.log(flatten(arr)) // [1, 2, 3, 4]
Looping array + recursion
Looping array + recursion

Implementation idea: loop the array, if there are arrays in the data, recursively call the flatten function (using the for loop to flatten), connect with concat, and finally return result;

function flatten(arr){
     var result = [];
     for(var i = 0, len = arr.length; i < len; i++){
         if(Array.isArray(arr[i])){
             result = result.concat(flatten(arr[i]));
         }else{
             result.push(arr[i]);
         }
     }
     return result;
 }
 
flatten(arr) // [1,2,3,4]

recursion

The first thing we can think of is to loop the array elements. If it is still an array, we can call the method recursively:

   var arr = [1, [2, [3, 4]]];
     
    function flatten(arr) {
        var result = [];
        for (var i = 0, len = arr.length; i < len; i++) {
            if (Array.isArray(arr[i])) {
                result = result.concat(flatten(arr[i]))
            }
            else {
                result.push(arr[i])
            }
        }
        return result;
    }
 
 
console.log(flatten(arr))

tostring

If the elements of the array are all numbers, then we can consider using the toString method because:

[1, [2, [3, 4]]].toString() // "1,2,3,4"

Calling the toString method returns a comma-delimited flat string. Now we can split it and convert it into a number to achieve flattening.

// Method 2
var arr = [1, [2, [3, 4]]];
 
function flatten(arr) {
    return arr.toString().split(',').map(function(item){
        return +item
    })
}
 
console.log(flatten(arr))
However, this method has very limited usage scenarios. If the array is [1, '1', 2, '2'], this method will produce wrong results.

reduce

Since we are processing an array and returning a value, we can consider using reduce to simplify the code:

// Method 3
var arr = [1, [2, [3, 4]]];
 
function flatten(arr) {
    return arr.reduce(function(prev, next){
        return prev.concat(Array.isArray(next) ? flatten(next) : next)
    }, [])
}
 
console.log(flatten(arr))
ES6 adds a spread operator to extract all traversable properties of the parameter object and copy them to the current object:

var arr = [1, [2, [3, 4]]];
console.log([].concat(…arr)); // [1, 2, [3, 4]]

We can only flatten one layer using this method, but if we keep thinking along this line, we can write a method like this:

var arr = [1, [2, [3, 4]]];
 
    function flatten(arr) {
     
        while (arr.some(item => Array.isArray(item))) {
            arr = [].concat(...arr);
        }
     
        return arr;
    }
     
    console.log(flatten(arr))

undercore

So how do we write an abstract flat function to facilitate our development? It's time for us to copy underscore again~

The source code and comments are given directly here, but please note that the flatten function here is not the final _.flatten. In order to facilitate multiple API calls, more configurations are made for flattening.

	/**
	 * Array flattening * @param {Array} input The array to be processed * @param {boolean} shallow Whether to flatten only one layer * @param {boolean} strict Whether to strictly process elements, explained below * @param {Array} output This is a parameter passed for the convenience of recursion */

	function flatten(input, shallow, strict, output) {

    // Output is used when used recursively
    output = output || [];
    var idx = output.length;

    for (var i = 0, len = input.length; i < len; i++) {

        var value = input[i];
        // If it is an array, process it if (Array.isArray(value)) {
            // If only one layer is flattened, traverse the array and fill in output accordingly
            if (shallow) {
                var j = 0, len = value.length;
                while (j < len) output[idx++] = value[j++];
            }
            // If all are flattened, recurse and pass in the processed output, and then process the output recursively
            else {
                flatten(value, shallow, strict, output);
                idx = output.length;
            }
        }
        // Not an array, decide whether to skip processing or put it into output based on the value of strict
        else if (!strict){
            output[idx++] = value;
        }
    }

    return output;

}

Explain strict. We can see in the code that when traversing array elements, if the element is not an array, the result of strict negation will be judged. If strict is set to true, it will be skipped without any processing, which means that non-array elements can be filtered. For example:

var arr = [1, 2, [3, 4]];
console.log(flatten(arr, true, true)); // [3, 4]

So what is the use of setting strict? Don't worry, let's first look at the results corresponding to various values ​​of shallow and strct:

shallow true + strict false : normal flat layer

shallow false + strict false : flatten all layers normally

shallow true + strict true : remove non-array elements

shallow false + strict true : returns a []

Let's see which methods in underscore call the basic function flatten:

_.flatten

The first is _.flatten:

_.flatten = function(array, shallow) {
    return flatten(array, shallow, false);
};
In normal flattening, we don't need to remove non-array elements.

_.union

This function takes multiple arrays and returns the union of the arrays passed in.

For example:

_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2, 3, 101, 10]

If the passed parameter is not an array, it will be skipped:

_.union([1, 2, 3], [101, 2, 1, 10], 4, 5);
=> [1, 2, 3, 101, 10]

To achieve this effect, we can flatten all the arrays passed in and then remove duplicates. Since only arrays can be passed in, we can directly set strict to true to skip the non-array elements passed in.

function unique(array) {
   return Array.from(new Set(array));
}
 
_.union = function() {
    return unique(flatten(arguments, true, true));
}

_.difference

Do you think it’s useful to mess with strict? Let’s look at _.difference:

The syntax is:

_.difference(array, *others)

The effect is to take out the elements from the array that are not present in multiple other arrays. Like _.union, elements that are not arrays are excluded.

For example:

_.difference([1, 2, 3, 4, 5], [5, 2, 10], [4], 3);
=> [1, 3]

The implementation is also very simple, flatten the array of others and filter out the values ​​in array that are not in the flattened array:

function difference(array, ...rest) {
 
    rest = flatten(rest, true, true);
 
    return array.filter(function(item){
        return rest.indexOf(item) === -1;
    })
}
If it is helpful to you, you are welcome to follow me. I will update the technical documentation regularly so that we can discuss and learn together and make progress together.

Summarize

This article ends here. I hope it can be helpful to you. I also hope you can pay more attention to more content on 123WORDPRESS.COM!

You may also be interested in:
  • JS array deduplication details
  • Detailed discussion of several methods for deduplicating JavaScript arrays
  • In-depth study of JavaScript array deduplication problem
  • JavaScript array deduplication solution
  • js implements array flattening
  • JavaScript Interview: How to implement array flattening method
  • 5 JavaScript Ways to Flatten Arrays
  • Introduction to JavaScript array deduplication and flattening functions

<<:  Detailed explanation of the difference and application of CSS3 filter:drop-shadow filter and box-shadow

>>:  Enterprise-level installation tutorial using LAMP source code

Recommend

Some thoughts and experience sharing on web page (website) design and production

First, before posting! Thanks again to I Want to S...

CSS3 realizes the glowing border effect

Operation effect: html <!-- This element is no...

How to hide rar files in pictures

You can save this logo locally as a .rar file and...

Example code for implementing equal width layout in multiple ways using CSS

The equal-width layout described in this article ...

SystemC environment configuration method under Linux system

The following is the configuration method under c...

mysql5.7.21.zip installation tutorial

The detailed installation process of mysql5.7.21 ...

The implementation process of extracting oracle data to mysql database

In the migration of Oracle database to MySQL data...

A preliminary understanding of CSS custom properties

Today, CSS preprocessors are the standard for web...

How to modify the time in centos virtual machine

The one above shows the system time, and the one ...

Detailed explanation of MySQL injection without knowing the column name

Preface I feel like my mind is empty lately, as I...

How to reset MySQL root password

Table of contents 1. Forgot the root password and...

MySQL transaction details

Table of contents Introduction Four characteristi...

MySQL 8.0.15 installation and configuration graphic tutorial under Win10

This article records the installation and configu...