두번째 코스(2) - 배열 관련메소드

Edwin·2023년 1월 28일
0
post-thumbnail
  • 본내용은 코딩앙마 강의를 요약정리한 것입니다.
  • 악마와 함께란? 매력적인 마성을 지니신 코딩앙마 코치님께 돌리는 구독자의 애정표현
    코딩앙마 중급강좌

악마와 함께 코딩을 Javascript 두번째 코스, 두번째-MainDish

07 배열관련 내장메소드

이전 기초강좌에서 배열에 데이터를 추가하고, 삭제하는 방법에 대해서 학습했었다.

  • push
  • unshift
  • pop
  • shift

배열 관련 메소드(1) 배열의 내용 잘라내기

splice

let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.splice(n, m) : n부터 m개를 지워라. 


3번지부터 시작되는 3, 4, 5, 6 이 배열에서 제거된 것을 볼 수 있다.

let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.splice(n, m, x) : n부터 m개를 지워라. 그 자리에 x를 채워라


이때 새롭게 추가되는 x는 지워진 m보다 그 길이가 작아도 되고 동률이어도 되며 길어도 상관없다. 이때, m에 숫자 0을 입력하면 제거할 것이 없이 내용을 단순하게 해당 위치에 추가하는 기능도 가능하다. 그런데 여기서 삭제된 요소들만 따로 변수로 지정할 수 있을까? 가능하다.

위의 이미지에서 볼 수 있듯이, 잘라낸 배열을 변수(deleteArr)에 담아서 콘솔에 기록해 보니 확인이 가능하다. 그런데 잘라내기를 실행했기에 콘솔의 위치를 splice가 실행된 이후에 기록했다면 TDZ에 의하여 다음과 같이 본래의 자료가 가공된 상태로 출력되는 배열과 요소를 볼 수 있다.

배열 관련 메소드(2) 배열의 내용 일부만 추출하기

그렇다면, 본래 배열의 요소를 수정하지 않으면서, 해당 내용만 추출할 수 있을까? 문자열 메소드에서 등장했던 slice(n,m)은 배열에서도 사용이 가능하다.

slice

let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(arr.slice(n, m))


배열의 n(3)번지로부터 m(6)번지 직전까지의 요소를 가져오는 것을 볼 수 있다. m을 기록하지 않으면 끝까지를 가져온다.

배열 관련 메소드(3) 이전배열에 추가 요소 더하여 합치기 .concat()

concat

let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(arr.concat(["A","B","C","D","E"]));

오늘의 코딩테스트를 하면서 학습했던 spread도 같은 효과를 발생시킨다.

그런데 concat 유심해서 볼 필요가 있다.

1) 먼저 선언된 arr에 바로 concat()을 한다고 해도 본래의 arr에는 변화가 없다. console.log(arr); 로 확인한 결과를 살펴보라. 오른쪽 콘솔의 첫번째 결과이다.

2) 다만 변수arr2에 arr.concat()을 실행하고, arr2를 출력했을 때에야 내용이 할당된 것을 볼 수 있다. 즉 arr.concat()로는 기존에 arr에 할당된 값에 초기화하며 재할당할 수 없는 것 같다.

3) console.log(arr.concat()); 을 하면, 결과물 자체는 바로 확인할 수 있다. 오른쪽 콘솔의 세번째 결과이다.

그렇다면 concat과 spread의 차이가 있지 않을까 질문이 든다. 그리고 이전에 기초강좌에서 배웠던 push와의 차이점은 무엇이 있을까? 결과를 통해서 살펴보자.

첫번째, concat()

const arr1 = [1,2,3];
const arr2 = [10,20,30];
const arr3 = [100,200,300];

const arr4 = arr1.concat(arr2,arr3);
console.log(arr4);

두번째, spread

spread

const arr1 = [1,2,3];
const arr2 = [10,20,30];
const arr3 = [100,200,300];

const arr4 = [...arr1, ...arr2, ...arr3]
console.log(arr4)

여기서 볼 때, concat()과 spread 자체는 동일한 결과를 추출하는 것 같다. 그러나 찾아보면, 대용량 결과를 취급할 때 처리 속도의 차이에서 concat()과 spread이 추출에 걸리는 시간이 다소 있는 것 같다. 초대용량을 취급할 때는 concat()이 우수하고, 작은용량을 취급할 때는 spread가 우세한 것으로 보여진다.


출처 : kir93.tistory

세번째, push()

const arr1 = [1,2,3];
const arr2 = [10,20,30];
const arr3 = [100,200,300];

const arr4 = [];
arr4.push(arr1,arr2, arr3);
console.log(arr4)


const arr5 = [];
arr5.push(...arr1,...arr2, ...arr3);
console.log(arr5)


push() 자체로는 내용을 추가하려면 새로운 배열arr4를 만들어야 하고, 그 안에 내용을 추가해야 한다. 그런데 이렇게 되면 출력값에 문제가 있다. arr4 = [ [arr1] , [arr2] , [arr3] ]과 같이 들어간다는 점이다. arr4배열 자체는 데이터를 3개 가지고 있고, 그 3개는 각각의 요소로 또다른 배열을 가지고 있는 셈이다. push()를 통해서 위와 같은 효과를 내기 위해서는 다른 방법을 사용해야 한다.

해당 방법은 push()와 spread를 함께 사용하는 arr5의 방법이다.

kir93.tistory님에 따르면, 처리 속도가 가장 처참하다. 만개의 요소(10k)를 처리하는데 있어서

  • push()와 spread : 1초당 4092개의 데이터만 처리할 수 있다는 건가?
  • spread : 그렇다고 하면, 해당계산은 1초당 6278개가 가능하고
  • concat() : 1초당 9780개의 데이터 처리가 가능하다는 것이다.(?)

ops/sec은 어떻게 읽어야 되는지 모르겠지만, 위와 같이 읽었을 때, push()와 spread는 가장 느린 배열 합치기 방법인 것으로 판단된다.

배열 관련 메소드(4) 반복문 추가로 배우기 forEach()

forEach

이전 기초강좌에서 배열의 반복문으로는 for 또는 for (of)를 학습했다. 이번에는 forEach()이다.

이번에는 출력을 콘솔이 아니라, document에 기록해보자. 이전에 학습했던 for (of)는 배열에서 index를 제거하기에 index를 알 수 없다고 배웠다. 그런데 forEach()메소드는 index를 추가하여 내용을 다룰 수 있다.

const arr = [100,200,300];

arr.forEach((parameter1, parameter2) => 
  {document.write(`(${parameter2}) ${parameter1} <br>`)}
);
  • forEach(parameter1, parameter2)
  • parameter1 : 배열의 내용을 가르킨다.
  • parameter2 : 새로운 index 번호를 부여한다.
  • parameter3 : 배열 전체를 가져온다.(메소드의 내용으로만 알고 있자.)

배열 관련 메소드(4) 배열의 위치 확인하기

indexOf
lastIndexOf

해당내용은 문자열 내장 메소드를 살펴보며 보았던 내용과 같이 사용된다.

let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.indexOf(3);

1) 배열내에 해당 데이터가 있으면 해당 데이터의 index를 반환하고
2) 배열내에 해당 데이터가 없으면 -1을 반환한다.

let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
console.log(arr.indexOf(0))
console.log(arr.lastIndexOf(0))

inCludes

1) indexOf()는 해당 내용을 앞에서부터 찾고
2) lastIndexOf()는 해당 내용을 뒤에서부터 찾는다.

let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
console.log(arr.includes(10))

1) includes() 내용이 있으면 true
2) includes() 내용이 없으면 false

배열 관련 메소드(5) 배열 내용 찾기 + 함수

find

1) find(fn), 첫번째 내용만 반환하고, 없으면 undefinded 를 반환
2) findIndex(fn), 위에는 내용을, 해당메소드는 index를 반환한다.

let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0];

console.log(arr.find((num) => {
  		return num === 4; }
  )
);

find((num) => {return num === 4;}, 이와 같이 찾고자 하는 num이 4와 같다면 반환하라는 함수로 배열에 있는 내용을 찾을 수 있다. 그런데 이 find는 배열에 담겨있는 객체에도 접근하여 원하는 정보를 추출할 수 있다. student배열에 3명의 학생과 수학점수가 있다. 원하는 정보를 찾아보자.

let student = [
  { name : "Edwin", Mathpoint : 20 },
  { name : "jun", Mathpoint : 40 },
  { name : "lee", Mathpoint : 60 },
]

const result = student.find((student)=> {
  if (student.Mathpoint < 50) {
    return true;
  } else {
    return false;
  }
});

console.log(result)


그런데 find는 해당 조건에 해당하는 Edwin을 찾았기에 바로 종료를 하였다. 50점 아래인 jun은 찾아내지 못했다. 이는 find가 배열에서 하나를 찾으면 바로 종료하기 때문이다. 그렇다면 어떻게 해야할까?

filter

let student = [
  { name : "Edwin", Mathpoint : 20 },
  { name : "jun", Mathpoint : 40 },
  { name : "lee", Mathpoint : 60 },
]

const result = student.filter((student)=> {
  if (student.Mathpoint < 50) {
    return true;
  } else {
    return false;
  }
});

console.log(result)


결과는 find와 다르게 해당되는 모든 학생명단(객체)을 추출하였다. 그렇다면 이름만 추출이 가능할까? 새로운 빈 배열에 내용을 할당하여 아래와 같이 추출해 보았다.

배열 관련 메소드(6) 배열 뒤집기, reverse()

let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(arr.reverse());

배열 관련 메소드(7) 배열 가공하기, map()

배열에 있는 정보에 하나씩 접근해서 함수 내용에 있는 과정을 처리하겠다는 건데, 많이 어렵다. 오늘의 코딩테스트 한줄에서 언급한 적 있지만, 어렵다.

기존의 배열에, 해당 학생이 최하점 50점을 넘었다면, true를 아니면 false를 기록하고 싶을 때, 즉 배열에 특정한 결과에 따라 property를 추가하고 싶을 때, map()를 사용하면 된다.

let student = [
  { name : "Edwin", Mathpoint : 20 },
  { name : "jun", Mathpoint : 40 },
  { name : "lee", Mathpoint : 60 },
];

let passStudents = student.map((students, index) => {
  return Object.assign({}, students, {
    pass : students.Mathpoint > 50,
  });
});

console.log(passStudents)

만약에 학생의 고유 id까지 property로 추가하고 싶으면 let passStudents에 id property를 아래와 같이 추가하면 된다.

let passStudents = student.map((students, index) => {
  return Object.assign({}, students, {
    id: index + 1,
    pass : students.Mathpoint > 50,
  });
});

배열 관련 메소드(8) 배열, 문자열로 합치기, join()

let str = ["아름다운", "마음들이", "모여서"]
let result = str.join()
console.log(result)


join()의 초기값은 위와 같이 ,(콤마)이다. 이를 만약 띄어쓰기를 추가하여 기록하고 싶다면 설정을 해주어야 한다.

let str = ["아름다운", "마음들이", "모여서"]
let result = str.join(" ")
console.log(result)

배열 관련 메소드(8) 문자열, 배열로 만들기, split()

let str = "아름다운 마음들이 모여서"
let result = str.split(" ")
console.log(result)

(" ")은 어떤 것을 기준으로 나눌지이다. ("")빈공간이 없다면 하나씩 나눌 것이다.

배열 관련 메소드(9) 배열인지 아닌지 확인하기.

isArray

let student = { name : "Edwin", Mathpoint : 20 };
let arr = [1,2,3,4,5]
let name = [
  { name : "Edwin", Mathpoint : 20 },
  { name : "jun", Mathpoint : 40 },
  { name : "lee", Mathpoint : 60 },
];


console.log(typeof student);
console.log(typeof arr);
console.log(typeof name);

기존의 지식으로 보면 student는 객체이고, name은 배열이다. 그런데 콘솔로 확인해 보면 3개다 전부 객체로 출력된다. 그렇다면 우리는 어떻게 해당 내용이 배열인지 확인할 수 있을까? Array.isArray()

let student = { name : "Edwin", Mathpoint : 20 };
let arr = [1,2,3,4,5]
let name = [
  { name : "Edwin", Mathpoint : 20 },
  { name : "jun", Mathpoint : 40 },
  { name : "lee", Mathpoint : 60 },
];


console.log(Array.isArray(student));
console.log(Array.isArray(arr));
console.log(Array.isArray(name));


student는 객체이기에, false가 나왔고 나머지는 true가 나오는 것을 볼 수 있다. 이렇게 함으로 해당 변수가 배열인지 아닌지 판단할 수 있다.

배열 관련 메소드(10) 배열을 정렬하자, sort()

sort

그런데 sort() 사용시 유의해야 할 점이 있다. 배열 자체를 정렬 상태로 변경한다는 점이다.

let arr = [1 ,5 ,7, 12,2 ,8, 2, 100,10];
arr.sort();
console.log(arr);

결과는 어떻게 나왔을까? [1,10,100,12,2,2,5,7,8] 이다. 뭔가 이상하다. 숫자가 한 자리, 두 자리, 세 자리 혼용되어 있을 때, sort()가 제대로 작동하지 않는다. 이럴 때는 함수를 사용하여 보다 구체적으로 정렬을 시킬 수 있다. 강의에 따르면 숫자형 자료라고 할지라도 문자열 자료로 취급하기에, 첫자리만 대상으로 삼고 정렬을 하는 메소드의 한계라고 지적하였다.

let arr = [1 ,5 ,7, 12,2,8, 2, 100,10];
arr.sort((a,b) => a - b);
console.log(arr);

결과는 [1,2,2,5,7,8,10,12,100] 에서 볼 수 있는 것과 같이 바르게 나왔다. 함수의 작동원리는 어떻게 될까? a-b를 빼주고, 양수인지 음수인지를 반환하라는 명령이라고 한다.

순서대로

  • 1, 5 를 비교하면, -4(음수)임으로 1이 5보다 작다. [1,5...]
  • 5, 7 을 비교하면, -2(음수)임으로 5가 7보다 작다. [1,5,7...]
  • 7, 12 를 비교하면, -5(음수)임으로 7이 12보다 작다. [1,5,7,12....]
  • 12 ,2 를 비교하면, 10(양수)임으로 12가 2보다 크다. 그런데 12를 기준으로 했을 때 2(-10)는 7(-5)보다, 5(-7)보다도 작지만, 1(-11)보다는 크기에 배열의 순서가 변경된다. [1,2,5,7,12...]

이러한 순으로 정렬이 이뤄진다. 그러나 이러한 계산이 복잡하기 때문에 별도로 사용하는 라이브러리가 있다. Lodash lib 그것이다. 설치를 위해서는 CDN으로 연결해 주는 것이 가장 빠른 방법이다. 서버에서 사용한다면, 터미널에 명령어를 선언하면 된다.

_.sortBy()

<script 
src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js">
</script>
npm install --save lodash

이제 쉽게 배열을 정렬해 보자.

let arr = [1 ,5 ,7, 12,2,8, 2, 100,10];
console.log(_.sortBy(arr));

배열 관련 메소드(11) 배열 내용을 합쳐보자, reduce()

reduce()

arr = [1, 2, 3, 4, 5] 배열이 주어였다고 하다. 해당 내용의 인수를 합치는 방법에는 무엇이 있을까? 첫번째는 반복문을 통해서 적용할 수 있을 것이다.

let arr = [1, 2, 3, 4, 5];
let result = 0;
arr.forEach((num) => {
   result = result+num;})

console.log(result)

해당 구문은 arr.forEach((num) => result+=num) 로도 단축이 가능하며, 결과는 15가 나올 것이다. 이 작업을 한 번에 처리하는 것이 reduce이다.

let arr = [1, 2, 3, 4, 5];
console.log(
  arr.reduce((prev, cur) => {
  return prev+cur;
  }, 0)
)
  • arr.reduce((prev, cur) => {return prev+cur;}, 0)
  • arr.reduce((누적계산값, 현재값) => {return prev+cur;}, 초기값)

초기값이 0인데, 이를 변수에서 하나씩 가져온 값으로 초기값(누적계산값)에 더해준다는 것이다. 초기값이 0이기에, 0+1은 1이다. 이후 누적계산값은 1이 되고, 1+2가 실행되어 3이 되며, 다음 누적계산값은 3, 그리고 3+3 = 6으로 순차적으로 reduce()가 실행된다. 초기값을 설정하지 않으면 배열의 첫 자리가 기록될 것이다. 실제적인 예를 만들어 보자, 이전에 map()통해서 했던 것이기도 한데, reduce()로 살펴보자.

let arr = [
  {name : 'Adwin', age : 10},
  {name : 'Bdwin', age : 15},
  {name : 'Cdwin', age : 20},
  {name : 'Ddwin', age : 25},
  {name : 'Edwin', age : 30},
  {name : 'Fdwin', age : 35},
  ];

let result = arr.reduce((prev, cur) => {
  if(cur.age >= 20) {
  prev.push(cur.name);}
  return prev;}, []);

console.log(result)

reduce()를 사용한다는 것은 초기값 설정의 유무에 달려 있다. 쉬에서 살펴본 예시에서 단순하게 더하는 경우에는 초기값이 중요하지 않을 수 있다. 그러나 바로 위의 예시에서 살펴본 것과 같이다. 배열에 담겨진 객체로부터 특정한 조건에 부합하는 새로운 배열을 만들고 싶을 때는 초기값으로 빈배열을 위와 같이 설정해 주어야 한다. 그리고 반드시 reduce((prev, cur) => 와 같이 함수의 parameter를 잘 기록해주어야 한다. cur.name이란 배열의 객체들이 순차적으로 들어온다는 것이고, prev.push는 조건문에서 통과한 객체들을 초기값인 빈 배열에 추가하겠다는 의미이다. 이를 통해 reduce()는 배열의 길이만큼 반복하며 해당 내용을 수행한다. 결과는 어떻게 나왔을까? 배열 안에 조건에 부함되는 인자들이 기록된 것을 볼 수 있다.

  • ["Cdwin","Ddwin","Edwin","Fdwin"]

만약에 객체로 구성된 배열을 새로 만들고 싶다면, let result 부분을 아래와 같이 property로 만들어주면된다.

let result = arr.reduce((prev, cur) => {
  if(cur.age >= 20) {
  prev.push({name:cur.name, age:cur.age});}
  return prev;}, []);

만약에 객체로 구성된 배열에 담겨신 나이의 총합을 구하고 싶다면 어떻게 하면 될까?

let result = arr.reduce((prev, cur) => {
  return prev+=cur.age;
  }, 0);

이와 같이 기록하면, 나이의 합게인 135를 산출할 수 있다. 각 상황에 따라서 개발자가 사용하시면 된다.

author. EDWIN
date. 23/01/28

profile
신학전공자의 개발자 도전기!!

0개의 댓글