JS array basic operation - how many ways are there for array traversal?

1, Basic traversal of array

This section introduces the four most commonly used traversal methods.

1.for...in

For... in is actually an object traversal method, not array specific. Using for... in will loop through all enumerable properties of the object itself and properties inherited from its constructor prototype. The traversal order is consistent with the list obtained by the Object.keys() function.

This method will traverse the non numeric subscript elements in the array and ignore the empty elements:

let list = [7, 5, 2, 3]
list[10] = 1
list['a'] = 1
console.log(JSON.stringify(Object.keys(list)))

for (let key in list) {
  console.log(key, list[key])
}

Output:

> ["0","1","2","3","10","a"]
> 0, 7
> 1, 5
> 2, 2
> 3, 3
> 10, 1
> a, 1

This method is the most difficult to traverse the array. It is usually orderly, but because it traverses according to the enumeration order of objects, that is, the specification does not specify the order, the specific implementation is carried out by the browser.
It is recommended not to rely on its traversal order.

2.for...of

This method is used to iterate over the iteratable object. It is used to traverse the array in order, and the iterated value is the value of the array. This method does not traverse non numeric subscript elements and does not ignore empty elements of the array:

let list = [7, 5, 2, 3]
list[5] = 4
list[4] = 5
list[10] = 1
// At this time, subscripts 6, 7, 8 and 9 are empty elements
list['a'] = 'a'

for (let value of list) {
  console.log(value)
}

Output:

> 7
> 5
> 2
> 3
> 5
> 4
>   //Traverse empty elements
>  //Traverse empty elements
>  //Traverse empty elements
>  //Traverse empty elements
> 1

3. Take the array length for traversal

This method is more like method 2. It is ordered and will not ignore empty elements.

let list = ['a', 'b', 'c', 'd']
list[4] = 'e'
list[10] = 'z'
list['a'] = 0

for (let idx = 0; idx < list.length; idx++) {
  console.log(idx, list[idx])
}

Output:

> 0, a
> 1, b
> 2, c
> 3, d
> 4, e
> 5, //Empty element
> 6, 
> 7, 
> 8, 
> 9, 
> 10, z

4.forEach traversal

forEach is a high-order function of an array. Its usage is as follows:

arr.forEach(callback[, thisArg])

Parameter Description:

  • callback
    The function executed for each element in the array, which receives three parameters:
  • currentValue
    The current element being processed in the array.
  • index optional
    The index of the current element being processed in the array.
  • array optional
    The array being manipulated by the forEach() method.
  • thisArg optional
    Optional parameters. Used as the value of this (reference object) when the callback function is executed.

Forach traverses the array in ascending order of array subscripts, and ignores empty elements:

let list = ['a', 'b', 'c', 'd']
list[4] = 'e'
list[10] = 'z'
list['a'] = 0

list.forEach((value, key, list) => {
  console.log(key, value)
})

Output:

> 0, a
> 1, b
> 2, c
> 3, d
> 4, e
> 10, z

There is a detail that is easy to ignore. We should try our best to avoid taking, adding and deleting elements of the array in traversal, otherwise there will be some unexpected situations, and different traversal methods will have different performances.

Delete elements in for... of and forEach Traversals
For example, delete elements in for... of traversal:

let list = ['a', 'b', 'c', 'd']

for (let item of list) {
  if (item === 'a') {
    list.splice(0, 1)
  }
  console.log(item)
}

Output:

> a
> c
> d

Delete elements in forEach traversal:

let list = ['a', 'b', 'c', 'd']

list.forEach((item, idx) => {
  if (item === 'a') {
    list.splice(0, 1)
  }
  console.log(item)
})

Output:

> a
> c
> d

It can be seen that the two are consistent. When traversing to a, delete a, B will be skipped, and adding elements is slightly different.

Add elements in for... of and forEach traversal
Add elements in for... of traversal:

let list = ['a', 'b', 'c', 'd']
for (let item of list) {
  if (item === 'a') {
    list.splice(1, 0, 'e')
  }
  console.log(item)
}

Output:

a
e
b
c
d

Add elements in forEach traversal:

let list = ['a', 'b', 'c', 'd']

list.forEach((item, idx) => {
  if (item === 'a') {
    list.splice(1, 0, 'e')
  }
  console.log(item)
})

Output:

a
e
b
c

Eh, a'd 'is missing! It can be seen that the number of forach traversals has been determined at the beginning, so the last'd 'is not output. This is a difference between forach and for traversing the array. Another important difference is that forEach is not available to interrupt loops such as break, continue and return, while for can.

In short, in the process of traversing the array, you should be very careful about the operation of the array, which is very similar to python and js, because in the two languages, the object / dictionary and array are references and variable objects.

2, Traversing arrays using higher-order functions

The above four kinds of traversal methods are relatively standard. However, there are many high-order functions for arrays in JS. In fact, these functions can achieve the purpose of traversing arrays, but the application scenarios of each function are different. Here is a brief introduction.

1. map

The parameters of the map() method are exactly the same as those of forEach, except that the map will collect the return values of the callback function to generate a new array.
For example, output 2 times of each element in the array as a new array:

let list = [1, 2, 3, 4]
let result = list.map((value, idx) => value * 2)
console.log(result) //Output [2,4,6,8]

2.filter

The filter() parameter is exactly the same as forEach, but its callback function should return a true or false value. The filter() method creates a new array that contains all the elements that make the callback return value true (different from true).
For example, filter even numbers in the array:

let list = [1, 2, 3, 4]
let result = list.filter((value, idx) => value % 2 === 0)
console.log(result) // Output [2,4]

3. find/findIndex

The find() method returns the value of the first element in the array that makes the callback return value true. If not, it returns undefined. It is very simple to use, such as finding the first even number in the array:

let list = ['1', '2', '3', '4']
let result = list.find(value => value % 2 === 0)
console.log(result) // Output 2

The findIndex() method is very similar to the find method, except that findIndex returns the index of the first element whose callback return value is true, and - 1 if there is no matching element. For example, find the subscript of the first even number in the array:

let list = [1, 2, 3, 4]
let result = list.findIndex(value => value % 2 === 0)
console.log(result) // Output 1

4.every/some

Both functions receive the same parameters as the above functions and return Boolean values.

  • every is used to determine whether each item in the array makes the return value of callback true,
  • some is used to determine whether there is at least one item so that the return value of the callback element is true.
let list = [1, 2, 3, 4]
// Determine whether each element in the array is less than 10
let result = list.every(value => {
  return value < 10
})
console.log(result) // Output true


//Determine whether each element is greater than 2
result = list.every(value => {
  return value > 2
})
console.log(result) // Output false

// Determine whether 1 exists in the array
result = list.some(value => {
  return value === 1
})
console.log(result) // Output true

// Determine whether there are numbers greater than 10 in the array
result = list.some(value => {
  return value > 10
})
console.log(result) // Output false

5.reduce/reduceRight accumulator

array.reduce(function(accumulator, currentValue, currentIndex, array), initialValue)

Parameters are different from other functions:
callback
The function that executes each value in the array contains four parameters:

  • accumulator
    The accumulator accumulates the return value of the callback; It is the cumulative value returned the last time the callback was called, or initialValue (see below).
  • currentValue
    The element being processed in the array.
  • currentIndex optional
    The index of the current element being processed in the array. If initialValue is provided, the starting index number is 0, otherwise it is 1.
  • array optional
    Array calling reduce()

initialValue optional

As the value of the first parameter when the callback function is called for the first time. If no initial value is provided, the first element in the array is used. Calling reduce on an empty array without an initial value will report an error.

The reduce() method executes a reducer function (executed in ascending order) provided by you for each element in the array to summarize its results into a single return value, while reducereight just traverses in the opposite order.

For example, a common requirement is to turn a list with the following structure into a tree structure, which can be easily realized by using forEach and reduce.

List structure:

let list = [
  {
    id: 1,
    parentId: ''
  },
  {
  	id: 2,
  	parentId: ''
  },
  {
  	id: 3,
  	parentId: 1
  },
  {
  	id: 4,
  	parentId: 2,
  },
  {
  	id: 5,
    parentId: 3
  },
  {
  	id: 6,
    parentId: 3
  }
]

Tree structure:

[
    {
        "id":1,
        "parentId":"",
        "children":[
            {
                "id":3,
                "parentId":1,
                "children":[
                    {
                        "id":5,
                        "parentId":3
                    },
                    {
                        "id":6,
                        "parentId":3
                    }
                ]
            }
        ]
    },
    {
        "id":2,
        "parentId":"",
        "children":[
            {
                "id":4,
                "parentId":2
            }
        ]
    }
]

Use reduce and forEach to convert list to tree structure:

function listToTree(srcList) {
  let result = []
  // reduce collects all node information and stores it in the object. It can be rewritten with forEach, but the code will be a few more lines
  let nodeInfo = list.reduce((data, node) => (data[node.id] = node, data), {})

 // forEach find mom for all elements
  srcList.forEach(node => {
    if (!node.parentId) {
      result.push(node)
      return
    }
    let parent = nodeInfo[node.parentId]
    parent.children = parent.children || []
    parent.children.push(node)
  })
  return result
}

The above is the basic array operations introduced in this paper around array traversal. In fact, these high-order functions can be used for array traversal (if you want to forcibly traverse, for example, the callback of some always returns false), but in actual use, different methods should be selected according to different needs.

Transferred from: https://wintc.top/article/8

Keywords: Javascript

Added by chrischen on Tue, 02 Nov 2021 09:17:51 +0200