본문 바로가기
Web development/Algorithm

[Javascript Cheet Sheet] Array객체, 반복문

by 자몬다 2021. 8. 25.

for...in, for...of

  
/** 
 * for문은 도중에 아이템을 제거해버리면 제대로 돌지 않는다.
 */
const arr = [1, 2, 3, 4, 5];
for(let item of arr){
    arr.shift();
    console.log(arr);
    console.log(item); // 1 3 5
}
/**
 * for of도 내부적으로는 for(let i = 0 ; i < arr.length ; i++) 이런식으로 동작하기 때문에,
 * 당연하게도 도중에 배열 아이템이 사라져버리면 배열 길이만큼 반복하지 않는다.
 * 이렇게 놓고 보면 당연한데도, 왜 내가 생각한 횟수만큼 돌지 않는지 고민했다. 멍청하게 헤매지 말자.
 * 
 * 원본 배열을 복제한 배열로 작업을 하던가, 
 * splice, pop, shift처럼 아이템을 삭제하는 대신
 * 값이 없음을 표현하는 값을 대입해서 사용하자.
 */

 /**
  * for of와 for in의 차이
  */
const arr2 = ['a', 'b', 'c'];
for(const item in arr2){
    console.log('in', item); // 0 1 2
}
for(const item of arr2){
    console.log('of', item); // a b c
}
/**
 * for in에서의 item은 배열의 index다.
 * for of에서의 item은 배열의 객체다.
 */
// for..of와 for..in의 차이점과 유의할 점

// for..of는 Array, Map, Set, String 등 반복가능한 객체에 대해 사용가능하다.
var arr = ['a', 'b', 'c'];
for (let i of arr) {
    console.log(i); // 'a', 'b', 'c'
}

// for..in은 객체의 반복을 위해 만들어진 메서드이며,
// 객체의 속성을 반환한다.
// *** 배열의 인덱스 반환용으로 만들어진 메서드가 아님에 주의!!
// 배열에 사용해도 i는 string 타입으로 반환된다.
// 또한 순서를 보장하지 않기 때문에 배열에서는 for, forEach, for..of를 사용하는 것이 좋다.
for (let i in arr) {
    console.log(i, typeof i); // '0', 'string'
}

 

forEach

반환값 undefined (메서드 체인 중간에 사용불가)

원본변경 X (callback에서는 가능)

반복중 배열 변경시 반복 생략됨

콜백함수 인자 (currentValue[, index[, array]]) 요소 값, 요소 인덱스, 순회 중인 배열

const array1 = ['a', 'b', 'c'];

array1.forEach(element => console.log(element));

// expected output: "a"
// expected output: "b"
// expected output: "c"

 

every, some

공통점

반환값 boolean

원본변경 X (callback에서는 가능)

콜백함수 인자 (currentValue[, index[, array]]) 요소 값, 요소 인덱스, 순회 중인 배열

 

차이점

every some
배열 안의 모든 요소가 주어진 판별 함수를 통과하는지 테스트
반복중 거짓인 경우 즉시 false 반환(나머지 인덱스는 반복하지 않음)
빈 배열에서 호출시 무조건 true 반환
배열 안의 어떤 요소라도 주어진 판별 함수를 통과하는지 테스트
반복중 참인 경우 즉시 true 반환(나머지 인덱스는 반복하지 않음)
빈 배열에서 호출시 무조건 false 반환
var arr = [1, 2, 3];

arr.every(item => item > 2); // false
arr.every(item => item > 0); // true

arr.some(item => item > 2); // true
arr.some(item => item > 3); // false

 

findIndex, indexOf, lastIndexOf

// 인덱스를 찾아 반환하는 함수들

const arr = [2, 5, 9, 2];

// findIndex
// 주어진 판별함수를 만족하는 첫번째 요소의 인덱스를 반환
// 없으면 -1
arr.findIndex((item) => item > 3); // 1
arr.findIndex((item) => item > 10); // -1

// indexOf
// 정해진 요소의 첫번째 인덱스를 반환
// 없으면 -1
arr.indexOf(2) // 0
arr.indexOf(10) // -1
// 두 번째 인자로 start index를 지정할 수 있다.
arr.indexOf(2, 1) // 3

// lastIndexOf
// 정해진 요소를 배열 맨 뒤에서부터 찾아 인덱스를 반환
// 없으면 -1
arr.lastIndexOf(2) // 3
arr.indexOf(10) // -1
// 두 번째 인자로 start index를 지정할 수 있다.
arr.indexOf(2, 2) // 0

 

flat(배열 평탄화)

매개변수는 얼마나 깊은 배열까지 평탄화할 것인지. default 1

const arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]

const arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]

const arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]

const arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr4.flat(Infinity);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

 

 

배열 요소 중복제거

(Symbol을 제외한)원시 자료형은 아래 방법으로 중복을 제거할 수 있다.

String, Number, BigInt, Boolean, undefined, null

// Set 사용
Array.from(new Set(arr));
// [...new Set(arr)] 과 동일

// filter
arr.filter((item, index) => arr.indexOf(item) === index);

// reduce
arr.reduce(
  (unique, item) => (unique.includes(item) ? unique : [...unique, item]),
  []
);

참조 자료형은 위 방법으로 중복이 제거되지 않는다.

함수, 배열, 객체

배열이나 객체의 중복 제거를 원할시엔 JSON.parse(JSON.stringify(arr))를 사용하는 편법?이 존재한다.

var arr = [{a:1}, {a:1}];
var stringified = arr.map(a => JSON.stringify(a)); // ["{\"a\":1}", "{\"a\":1}"]
var unique = [...new Set(stringified)]; // ["{\"a\":1}"]
var result = unique.map(u => JSON.parse(u)); // [{a:1}]

// 축약
[...new Set(arr.map(a=>JSON.stringify(a)))].map(u=>JSON.parse(u));

 

splice

특정인덱스의 중간요소제거

/**
 * splice
 * 배열 기존 요소 삭제, 교체, 추가 (원본 변경)
 */
// arr.splice(인덱스, 교체할 갯수, [교체할 요소])
// 첫번째 인자 : 몇번째 인덱스에 넣을것인지
// 두번째 인자 : 0이면 교체하지 않고 추가만 함. 배열 길이보다 길면 인덱스 이후로 모두 제거
// 세번째 인자 : 교체할 요소가 없으면 삭제만 함
// 리턴값 : 제거된 요소들의 배열
arr.splice(1, 0, 100); // arr[1] 순서에, 아무것도 삭제하지 않고, 100을 추가
// arr = [1, 100, 2, 3];
// 리턴값 []

arr.splice(1, 2, 100); // arr[1]부터, 2개를 제거하고, 100을 추가
// arr = [1, 100];
// 리턴값 [2, 3];

arr.splice(1, 10); // arr[1]부터, 10개를 제거
// arr = [1];
// 리턴값 [2, 3];

/**
 * slice
 * 얕은 복사 후 새로운 배열로 반환함(원본 보존)
 */
arr = ["a", "b", "c", "d", "e"];
arr.slice(2);
// arr[2]부터 잘라서 반환함.
// ['c', 'd', 'e']

arr.slice(1, 3);
// arr[1] 이상 arr[3] 미만
// [b', 'c']

 

shift unshift pop push

배열 요소 추가 삭제

arr = [1, 2, 3];

/**
 * 원본 배열이 변경되는 방식
 */

// 배열 맨 뒤에 값 추가 & 배열 길이 반환
const pushed = arr.push(0);
// pushed = 4
// arr = [1, 2, 3, 0]

// 배열 맨 앞에 값 추가 & 배열 길이 반환
const unshifted = arr.unshift(0);
// unshifted = 4
// arr = [0, 1, 2, 3]

// 배열 맨 끝 값 제거 & 제거된 요소 반환
const popped = arr.pop();
// popped = 3
// arr = [1, 2]

// 배열 맨 앞 값 제거 & 제거된 요소 반환
const shifted = arr.shift();
// shifted = 1
// arr = [2, 3]

 

map, filter, reduce

별도로 정리해 둠 : map vs filter vs reduce 보러가기

 

댓글