티스토리 뷰

TIL

TIL 220727 배열 메소드 (Array Method)

2021bong 2022. 7. 27. 23:29

array.forEach()

주어진 함수를 배열 요소 각각에 대해 실행한다.

undefined을 반환하여 메소드 체인의 중간에 사용할 수 없다. 단순히 반복문을 대체하기 위한 함수라고 생각하면 된다.

const arr1 = ['a', 'b', 'c'];
arr1.forEach(element => console.log(element));
// "a" 
// "b"
// "c"

for문을 forEach()로 바꿔보기

// for문
const items = ['item1', 'item2', 'item3'];
const copy = [];
for (let i=0; i<items.length; i++) {
  copy.push(items[i]);
}
// forEach()
const items = ['item1', 'item2', 'item3'];
const copy = [];
items.forEach(function(item){
  copy.push(item);
});

 

 

array.map()

배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환한다.

const arr = [1, 4, 9, 16];
const map = arr.map(x => x * 2); // 요소에 2를 곱한 값을 반환
console.log(map); //[2, 8, 18, 32]

forEach()와 map()의 차이점

메소드만 다르게 똑같은 형태로 코드를 작성해도 반환값이 다르기 때문에 다른 결과가 나온다.

forEach는 undefined를 반환하고 map은 새로운 배열을 반환한다.

const arr = [1, 4, 9, 16];
const map = arr.map(item => item * 2);
console.log(map); //[2, 8, 18, 32]

const forEach = arr.forEach((item) => item * 2);
console.log(forEach); // undefined

 

 

Array.from()

유사 배열 객체(array-like object)나 반복 가능한 객체(iterable object)를 얕게 복사해 새로운 Array 객체를 만든다. 

새로운 Array 인스턴스를 반환한다.

// syntax

Array.from(arrayLike[, mapFn[, thisArg]])
// arrayLike: 배열로 변환하고자 하는 유사 배열 객체나 반복 가능한 객체
// mapFn: 배열의 모든 요소에 대해 호출할 맵핑 함수 
// thisArg: mapFn 실행 시에 this로 사용할 값 (보통 여기까지는 잘 사용하지 않는 것 같다.)

 

// String에서 배열 만들기
Array.from('foo'); // ["f", "o", "o"]

// Set에서 배열 만들기
const s = new Set(['foo', window]);
Array.from(s); // ["foo", window]

// Map에서 배열 만들기
const m = new Map([[1, 2], [2, 4], [4, 8]]); // *Map 객체 : 키-값 쌍의 모음
Array.from(m); // [[1, 2], [2, 4], [4, 8]]

 

// Array.from과 화살표 함수 사용하기
// 1
Array.from({length: 5}, (value, index) => index); // [0, 1, 2, 3, 4]
// 2
Array.from(Array(5), (_, index) => index); // [0, 1, 2, 3, 4]

1과 2는 같은 내용이다.

1. 배열은 사실 length 라는 속성을 가진 object이므로 반대로 object에 length속성을 넣어주게 되면 유사 배열로 인식되기 때문에 {length: 5}가 length가 5인 배열로 인식하여 작동한다. 하지만 length속성을 추가한 object가 배열과 같다는 이야기는 아니다. Array에는 배열로 동작하기위한 다른 메소드들이 담겨 있기 때문이다.

 

2. 불필요한 인자의 공간을 채우기 위한 용도로 맵핑 함수의 첫 번째 인자로 언더스코어(_) 를 사용할 수 있다.


array.filter()

주어진 함수의 테스트를 통과하는 모든 요소를 모아 새로운 배열로 반환한다.

어떤 요소도 테스트를 통과하지 못했으면 빈 배열을 반환한다.

// 6글자 이상인 요소만 남기기
const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
const result = words.filter(word => word.length > 6);
console.log(result); // ["exuberant", "destruction", "present"]

 

// 값이 10이하인 요소 제거하기
function isBigEnough(value) {
  return value >= 10;
}
let filtered = [12, 5, 8, 130, 44].filter(isBigEnough); 
// filtered는 [12, 130, 44]

 

 

 

array.find()

주어진 판별 함수를 만족하는 첫 번째 요소의 값을 반환한다.

그런 요소가 없다면 undefined를 반환한다.

원하는 데이터가 있는지 확인할 때 => 요소가 있다면 바로 배열을 빠져나오기 때문에 filter보다 빠르다.

// 10보다 큰 값이 있는지 확인하기
const arr = [5, 12, 8, 130, 44];
const found = arr.find(element => element > 10); 
console.log(found); // 12
// 객체로 이루어진 배열에서 name의 값이 'cherries'가 있는지 확인하기
const inventory = [
  {name: 'apples', quantity: 2},
  {name: 'bananas', quantity: 0},
  {name: 'cherries', quantity: 5}
];
const result = inventory.find(fruit => fruit.name === 'cherries');
console.log(result) // { name: 'cherries', quantity: 5 }

array.every()

배열 안의 모든 요소가 주어진 판별 함수를 통과하는지 테스트한다. (&&같은 개념이라고 생각하면 될 것 같다.)

Boolean 값을 반환하고 빈 배열에 호출하면 무조건 true를 반환한다.

// 모든 요소가 10보다 크거나 같은지 확인하기
function isBigEnough(element) {
  return element >= 10;
}
[12, 5, 8, 130, 44].every(isBigEnough);   // false
[12, 54, 18, 130, 44].every(isBigEnough); // true
const user = [{name: '짱구', age: 10}, {name: '철수', age: 10}, {name: '흰둥이', age: 2}]
// 모든 유저의 나이가 5살보다 큰지 확인하기
console.log(user.every((item)=> item.age>5)); // false

// 모든 유저의 나이가 1살보다 큰지 확인하기
console.log(user.every((item)=> item.age>1)); // true

 

 

 

array.some()

배열 안의 어떤 요소라도 주어진 판별 함수를 통과하는지 테스트한다.

어떤 배열 요소라도 대해 참인(truthy) 값을 반환하는 경우 true, 그 외엔 false를 반환한다. 빈 배열에서 호출하면 무조건 false를 반환한다. (||같은 개념이라고 생각하면 될 것 같다.)

// 10보다 크거나 같은 요소가 있는지 확인하기
function isBiggerThan10(element) {
  return element >= 10;
}
[2, 5, 8, 1, 4].some(isBiggerThan10);  // false
[12, 5, 8, 1, 4].some(isBiggerThan10); // true

 

const user = [{name: '짱구', age: 10}, {name: '철수', age: 10}, {name: '흰둥이', age: 2}]
// 5살보다 나이가 많은 유저가 있는지 확인하기
console.log(user.some((item)=> item.age>5)); // true

// 1살보다 나이가 많은 유저가 있는지 확인하기
console.log(user.some((item)=> item.age>1)); // true

 

// checkAvailability함수의 2번째 인자로 넣은 과일이 fruits에 있는지 확인하기
let fruits = ['apple', 'banana', 'mango', 'guava'];
function checkAvailability(arr, val) {
  return arr.some(arrVal => val === arrVal);
}
checkAvailability(fruits, 'grape'); //false
checkAvailability(fruits, 'banana'); //true

 

 

array.includes()

배열이 특정 요소를 포함하고 있는지 판별한다. Boolean값을 반환하며 대소문자를 구분한다.

// syntax

arr.includes(valueToFind[, fromIndex])
// valueToFind: 찾을 내용
// fromIndex: 찾기 시작할 인덱스

 

// 배열에서 첫번째 인자가 있는지 확인
[1, 2, 3].includes(2);     // true
[1, 2, 3].includes(4);     // false
[1, 2, NaN].includes(NaN); // true

 

fromIndex가 배열의 길이와 같거나 큰 양수일 때 => false를 리턴한다. 
fromIndex가 음수일 때 => (array.length + fromIndex)의 인덱스로 검색하는데 array.length + fromIndex가 음수면 0으로 취급되어 배열의 전체에서 검색한다.

[1, 2, 3].includes(3, 3);  // false 3이 있는지 3번 인덱스부터 판별
[1, 2, 3].includes(3, -1); // true (3, (3 + (-1))) => (3, 2);
[3, 2, 1].includes(3, -1); // false (3, (3 + (-1))) => (3, 2);
// fromIndex가 음수일 때 찾고자 하는 값의 위치에 따라서 결과가 달라질 수 있다.
[3, 2, 1].includes(3, -10); // true array.length + fromIndex가 -7이라서 0으로 취급

string.includes()였다면 pets.includes('at')가 true였겠지만 array.includes()는 false이다.

요소가 완벽하게 일치해야 true를 반환한다.

const pets = ['cat', 'dog', 'bat'];
console.log(pets.includes('cat')); // true
console.log(pets.includes('at')); // false

 

 

array.indexOf()

배열에서 지정된 요소를 찾을 수 있는 첫 번째 인덱스를 반환하고 존재하지 않으면 -1을 반환한다. ===을 사용하여 비교한다.

// syntax

arr.indexOf(searchElement[, fromIndex])
// searchElement: 찾을 요소
// fromIndex: 찾기 시작할 인덱스

 

const beasts = ['ant', 'bison', 'camel', 'duck', 'bison'];
console.log(beasts.indexOf('bison')); // 1 ('bison'의 인덱스)
console.log(beasts.indexOf('bison', 2)); // 4 (2번 인덱스부터 'bison'이 있는지 찾음)
console.log(beasts.indexOf('giraffe')); // -1 (해당하는 값이 없음)

array.sort()

배열의 요소를 적절한 위치에 정렬한 후 그 배열을 반환한다. 복사본이 만들어지는 것이 아닌 원본 배열이 정렬된다. 

정렬 속도와 복잡도는 각 구현방식에 따라 다를 수 있다. 기본적으로 오름차순으로 정렬되며 배열 요소를 문자열로 캐스팅하고 변환된 문자열을 비교하여 순서를 결정한다. undefined는 문자열로 변환되지 않아 맨 끝으로 정렬 된다.

// syntax

arr.sort([compareFunction])
// compareFunction: 정렬 순서를 정의하는 함수, 
// 생략하면 배열은 각 요소의 문자열 변환에 따라 각 문자의 유니 코드 코드 포인트 값에 따라 정렬

 

sort()를 사용하면 오름차순으로 정렬되는데 숫자의 경우 크기가 아니라 한자리씩 비교되어 100000이 21보다 앞에 오게 된다. (사전을 검색하는 방식처럼 정렬된다고 생각하면 될 것 같다.)

const months = ['March', 'Jan', 'Feb', 'Dec'];
months.sort();
console.log(months); // ["Dec", "Feb", "Jan", "March"]

const nums = [1, 30, 4, 21, 100000];
nums.sort();
console.log(nums); // [1, 100000, 21, 30, 4]

 

// compare 함수의 형식
function compare(a, b) {
  if (a > b) {
    return -1; // b가 앞에 옴
  }
  if (a < b) {
    return 1; // a가 앞에 옴
  }
  // a === b
  return 0; // 정렬 유지
}

 

숫자 정렬

// 오름차순 정렬
let numbers = [4, 2, 5, 1, 3];
numbers.sort(function(a, b) {
  return a - b;
});
console.log(numbers); // [1, 2, 3, 4, 5]
// 내림차순 정렬
let numbers = [4, 2, 5, 1, 3];
numbers.sort(function(a, b) {
  return b - a;
});
console.log(numbers); // [5, 4, 3, 2, 1]

 

문자 정렬

// 오름차순 정렬
let string = ["BA", "BB","AA", "AB", "CB", "CA"];
string.sort();
console.log(string); // ["AA","AB","BA","BB","CA","CB"]

// 내림차순 정렬 - 문자열은 숫자 정렬처럼 하면 정상적으로 정렬이 되지않아 비교 연산자를 사용해야함
string.sort(function compare(a, b) {
  return a == b ? 0 : a > b ? -1 : 1; // (조건문1) ? (조건문 1이 참일때) : (거짓일때 수행할 조건문2) ? (조건문 2 참일때) : (모두 거짓일 때)
});
console.log(string); // ["CB","CA","BB","BA","AB","AA"]

// 대소문자의 혼합 정렬
let newString = ["bA", "Bb","aa", "Ab", "cB", "ca"];
newString.sort(function compare(a, b) {
  let x = a.toUpperCase(),
      y = b.toUpperCase();
  
  return x == y ? 0 : x < y ? -1 : 1;
});
console.log(newString); // ["aa", "Ab", "bA", "Bb", "ca", "cB"]

 

 

array.reverse()

배열의 순서를 반전하며 원본 배열을 변형한다.

const a = [1, 2, 3];
console.log(a); // [1, 2, 3]

a.reverse();
console.log(a); // [3, 2, 1]

array.join()

배열의 모든 요소를 연결해 하나의 문자열로 만든다.

// syntax

arr.join([separator])
// separator: 배열의 각 요소를 구분할 문자열을 지정, 요소가 undefined 또는 null이면 빈 문자열로 변환

 

const elements = ['Fire', 'Air', 'Water'];
console.log(elements.join()); // "Fire,Air,Water" 지정하지 않으면 ,로 구분
console.log(elements.join('')); // "FireAirWater"
console.log(elements.join('-')); // "Fire-Air-Water"

 

 

array.concat()

인자로 주어진 배열이나 값들을 기존 배열에 합쳐서 새 배열을 반환한다. 인수가 배열이면 그 구성요소가 순서대로 붙고, 배열이 아니면 인수 자체가 붙는다. (깊이를 지정하면 계속해서 요소를 붙여주는 flat()이라는 메소드도 있었으나 concat()으로 충분할 것 같다.)

const array1 = ['a', 'b', 'c'];
const array2 = ['d', 'e', 'f'];
const array3 = array1.concat(array2);
console.log(array3); // ["a", "b", "c", "d", "e", "f"]

 

const arr = ['a', 'b', 'c'];
arr.concat(1, [2, 3]);
// ['a', 'b', 'c', 1, 2, 3]
// 배열이 아닌 1이 요소로 붙고 [2, 3]배열의 구성요소가 순서대로 붙음

array.slice()

어떤 배열의 begin부터 end까지(end 미포함)에 대한 얕은 복사본을 새로운 배열 객체로 반환한다. 원본 배열은 바뀌지 않는다.

// syntax

arr.slice([begin[, end]])
// begin: 반환할 배열의 시작인덱스
// end: end인덱스 앞까지, end가 생략되면 배열의 끝까지 추출

 

const animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];

console.log(animals.slice()); // ["ant", "bison", "camel", "duck", "elephant"] 
// 비워두면 전체를 반환

console.log(animals.slice(2)); // ["camel", "duck", "elephant"] 
// 2번인덱스부터 끝까지

console.log(animals.slice(-2)); // ["duck", "elephant"] 
// 음수: 뒤에서 부터 => 뒤부터 요소 2개만

console.log(animals.slice(100)); // []
// 배열의 길이와 같거나 큰 수 => 빈 배열

console.log(animals.slice(2, 4)); // ["camel", "duck"] 
// 2번 인덱스부터 4번 인덱스 앞(3번 인덱스)까지

console.log(animals.slice(1, 5)); // ["bison", "camel", "duck", "elephant"] 
// 1번 인덱스부터 5번 인덱스 앞(4번 인덱스)까지

console.log(animals.slice(2, -1)); // ["camel", "duck"] 
// 2번 인덱스부터 뒤에서 1개 요소를 빼고 까지

console.log(animals.slice(2, 100)); // ['camel', 'duck', 'elephant'] 
// 배열의 길이와 같거나 큰 수 => 배열 끝까지

 

 

array.splice()

배열의 기존 요소를 삭제 또는 교체하거나 새 요소를 추가하여 배열의 내용을 변경한다. 
원본 배열이 변경되고 제거한 요소를 담은 배열을 반환한다.

// syntax

array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
// start: 배열의 변경을 시작할 인덱스 
// deleteCount: 배열에서 제거할 요소의 수(생략하거나 배열길이보다 길면 start부터 모두 제거, 0이나 음수면 아무것도 제거하지 않지만 추가할 요소를 지정해야함)
// item: 배열에 추가할 요소, 지정하지 않으면 요소를 제거만 함

 

const months = ['Jan', 'March', 'April', 'June'];
months.splice(1, 0, 'Feb'); //  1번 인덱스에 아무것도 지우지 않고 'Feb'를 추가함
console.log(months); // ["Jan", "Feb", "March", "April", "June"]

// 원본 배열을 변경하기 때문에 months는 ["Jan", "Feb", "March", "April", "June"]가 됨
months.splice(4, 1, 'May'); // 4번 인덱스부터 1개를 지우고 'May'를 추가함
console.log(months); // ["Jan", "Feb", "March", "April", "May"]

 

start가 음수인 경우 배열의 끝에서부터 요소를 세어나간다.

즉 -n이면 요소 끝의 n번째 요소를 가리키며 array.length - n번째 인덱스와 같다.

(예제의 -2는 myFist배열의 끝의 2번째 요소인 'mandarin'을 가리키며 4 - 2 = > 2번째 인덱스와 같다.)

let myFish = ['angel', 'clown', 'mandarin', 'sturgeon'];
let removed = myFish.splice(-2, 1); // == (2, 1)

// splice를 한 원본 배열은 제거하고 남은 것들을 반환
console.log(myFish) // myFish = ["angel", "clown", "sturgeon"] 

// 원본 배열을 splice한 건 제거한 것들을 반환
console.log(removed) // removed = ['mandarin']

slice()와 splice()의 차이점

slice()는 원본 배열을 변경하지 않으며 새로운 배열을 반환한다.

// slice()
const color = ['red', 'black', 'white','pink','blue'];
let slice = color.slice(1, 2);
console.log(color) // ['red', 'black', 'white', 'pink', 'blue']
color.slice(1, 2);
console.log(color); // ['red', 'black', 'white', 'pink', 'blue']
console.log(slice); // ['black']

 

splice()는 원본 배열을 변경하며 제거한 요소의 배열을 반환한다.

// splice()
const color = ['red', 'black', 'white','pink','blue'];
let splice = color.splice(1, 2);
console.log(color); // ['red', 'pink', 'blue']
color.splice(1, 2);
console.log(color); // ['red']
console.log(splice); // ['black', 'white']


array.reduce()

배열의 각 요소에 대해 주어진 리듀서(reducer) 함수를 실행하고 누적 계산한 하나의 결과값을 반환한다.

보통 배열의 모든 값을 합산할 때 자주 사용하는 것 같다.

// syntax

arr.reduce(callback[, initialValue])

arr.reduce((acc, cur, idx, src) => { return result }, initialValue);

// 리듀서 함수는 네 개의 인자를 가짐
// 1. 누산기 accumulator (acc)  
// 2. 현재 값 currentValue (cur)  
// 3. 현재 인덱스 currentIndex (idx)  
// 4. 원본 배열 array (src)

// 리듀서 함수의 반환 값은 누산기에 할당되고, 누산기는 순회 중 유지되므로 결국 최종 결과는 하나의 값이 됨

 

initialValue를 설정했느냐 안했느냐에 따라 콜백의 최초 호출 시의 accumulator와 currentValue가 달라진다.

const array1 = [1, 2, 3, 4];
const initialValue = 0;
const sumWithInitial = array1.reduce(
  (previousValue, currentValue) => previousValue + currentValue,
  initialValue
  );
  
console.log(sumWithInitial); // 0 + 1 + 2 + 3 + 4 => 10

initialValue 설정을 했을 때의 콜백의 최초 호출 시의 accumulator와 currentValue

 

객체로 이루어진 배열에 들어있는 값을 합산하기 위해서는 반드시 초기값을 주어야 한다.

let initialValue = 0;
let sum = [{x: 1}, {x:2}, {x:3}].reduce(function (accumulator, currentValue) {
    return accumulator + currentValue.x;
},initialValue)
console.log(sum) // 6

 

그 외에도 그룹핑이나

let people = [
  { name: 'Alice', age: 21 },
  { name: 'Max', age: 20 },
  { name: 'Jane', age: 20 }
];
function groupBy(objectArray, property) {
  return objectArray.reduce(function (acc, obj) {
    let key = obj[property]
    if (!acc[key]) {
      acc[key] = []
    }
    acc[key].push(obj)
    return acc
  }, {})
}
let groupedPeople = groupBy(people, 'age')
// groupedPeople is:
// { 
//   20: [
//     { name: 'Max', age: 20 }, 
//     { name: 'Jane', age: 20 }
//   ], 
//   21: [{ name: 'Alice', age: 21 }] 
// }

 

sort, every, some, find, findIndex, includes도 다 reduce로 구현이 가능하며 비동기 프로그래밍을 할 때도 유용하다.

// == map()
const oneTwoThree = [1, 2, 3];
result = oneTwoThree.reduce((acc, cur) => {
  acc.push(cur % 2 ? '홀수' : '짝수');
  return acc;
}, []); // 초기값 = 빈 배열
result; // ['홀수', '짝수', '홀수']

// 홀수만 필터링 하는 코드 (== filter())
const oneTwoThree = [1, 2, 3];
result = oneTwoThree.reduce((acc, cur) => {
  if (cur % 2) acc.push(cur);
  return acc;
}, []);
result; // [1, 3]

// 비동기 프로그래밍
const promiseFactory = (time) => {
  return new Promise((resolve, reject) => {
    console.log(time); 
    setTimeout(resolve, time);
  });
};
[1000, 2000, 3000, 4000].reduce((acc, cur) => {
  return acc.then(() => promiseFactory(cur));
}, Promise.resolve());
// 바로 1000
// 1초 후 2000
// 2초 후 3000
// 3초 후 4000

 

반복되는 모든 것에는 reduce를 쓸 수 있다고 보면 된다. 구체적인 설명과 reduce사용예시는 링크링크에서 확인 가능하다.


배열 메소드를 정리하는데 비슷해서 비교되는 메소드들의 차이점까지 찾다보니 생각보다 시간이 엄청 걸렸다. reduce를 처음 접했을 때는 이해를 못했는데 알고보니 아주 대단한 메소드였던 것이다...!!! 비슷한 느낌의 메소드들끼리 묶어서 적어뒀는데 누군가에게 이 글이 도움이 되면 좋겠다😭

728x90
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함