본문 바로가기

[코드팩토리] 어레이 함수 (Array Functions)

codeConnection 2024. 3. 5.

Array 함수 타입은 Object 타입 다음으로 사용 빈도가 높은 함수이다.

이번 내용에서는 그 중에서도 사용빈도가 높은 어레이 함수에 대해 다룬다.

기본형

let 변수명 = ['인덱스0번에해당하는값', '2번값', '3번값'...]];
let iveMembers = [
    '안유진',
    '가을',
    '레이',
    '장원영',
    '리즈',
    '이서'
];

console.log(iveMembers);

위와 같이 Array 기본형으로 구성하면 아래와 같이 콘솔에 출력된다.

push()

Array의 가장 마지막 인덱스에 값을 추가하는 함수

기본형 : 변수명.push('추가할값');

 

let iveMembers = [
    '안유진',
    '가을',
    '레이',
    '장원영',
    '리즈',
    '이서'
];

console.log(iveMembers);

// push()
iveMembers.push('아이유');
console.log(iveMembers);

원래는 값을 6개 넣었기에 0번 인덱스부터 5번 인덱스까지 6개의 값이 존재하는 오브젝트 어레이였는데,

'아이유'를 6번 인덱스를 만들어 넣어 iveMembers라는 변수는 7개의 값을 갖게 되었다.

pop()

Array의 가장 마지막 인덱스를 삭제하고 반환해주는 함수

기본형 : 변수명.pop();

 

원래는 이서까지 6명의 멤버였는데, iveMembers.push('아이유') 를 통해 아이유를 추가했다.

그리고 콘솔에서 console.log(iveMembers.pop()); pop를 넣었더니 아이유를 반환했다.

그리고 다시 iveMembers를 콘솔에 출력해보니 아이유가 빠져있다.

shift()

Array의 가장 첫번째 인덱스를 삭제하고 반환해주는 함수

기본형 : 변수명.shift();

 

shift 함수를 사용하니 가장 첫번째인 0번 인덱스의 안유진을 반환했고, 다시 콘솔에 iveMembers를 확인해보니 안유진이 삭제되어있다.

unshift()

Array의 가장 첫번째 인덱스를 삭제하고 반환해주는 함수

기본형 : 변수명.unshift();

shift 함수의 반대. 가장 첫번째 인덱스에 새로운 값을 추가한다.

push()는 마지막 인덱스에 추가하는 것이고 가장 마지막 인덱스를 삭제하는 pop()와 대비되는데,

unshift()는 첫번째 인덱스에 추가하는 것이고 가장 첫번째 인덱스를 삭제하는 shift()와 대비된다.

iveMembers.unshift('안유진')으로 첫번째 인덱스에 안유진을 넣었더니 다시 어레이에 포함되었다.

splice()

(몇번 인덱스부터, 몇 개의 인덱스를) 한꺼번에 반환하고 삭제해주는 함수

기본형 : 변수명.splice(몇번인덱스, 몇개인덱스);

 

0번 인덱스부터 3개의 인덱스를 반환하고 삭제하라.

안유진, 가을, 레이가 반환되었고, 다시 콘솔에 iveMembers를 조회해보니  0~2번 인덱스 3개가 삭제되었다.

concat()

변수의 가장 마지막 인덱스에 값을 추가해주는 함수이다.

push()와 같아보이지만 차이는 push()는 마지막 인덱스에 추가하고 변수가 계속 추가된 채로 저장되지만,

concat()은 한 번만 추가하고 변수 자체의 값을 변경시키지는 않는다.

기본형 : 변수명.concat('추가할 값');

 

console.log(iveMembers.concat('아이유'));
console.log(iveMembers);

위 콘솔을 보면 아이유를 추가했을 때만 가장 마지막 인덱스에 값을 추가했고, 다시 콘솔로 iveMembers를 출력해보니 기존의 어레이는 변경되지 않음을 확인할 수 있다.

slice()

splice()와 같은 기능인데, 원래 array를 변경하지 않는 함수이다.

즉 (몇번 인덱스부터, 몇 개의 인덱스를) 한꺼번에 반환만하고 삭제를 하진 않는다.

기본형 : 변수명.slice(몇번인덱스, 몇개인덱스);

 

console.log(iveMembers.slice(0, 3));
console.log(iveMembers);

역시 0번 인덱스부터 3개의 값을 반환해주었다.

spread operator()

...으로 쓰는데, spread의 의미처럼 펼친다는 의미이다.

예제를 봐야 이해가 빠르다.

기본형 : ...변수명

 

let iveMembers2 = [
  iveMembers
];

console.log(iveMembers2);

위 예제를 보면 [[]] 형태로 리스트 iveMembers2라는 리스트 안에 iveMembers라는 리스트가 하나 더 들어갔다.

그런데 ... 를 사용해서 Spread operator를 사용하면

let iveMembers2 = [
  ...iveMembers
];

console.log(iveMembers2);

리스트를 벗겨내고서 상위 리스트에 펼쳐져서 들어간다.

그런데 재미있는 점은 그렇다면 iveMembers와 iveMembers2는 출력된 값은 같은데 콘솔에 같은지 확인해보면 False가 나온다.

console.log(iveMembers === iveMembers2);

그 이유는, ...spread operator를 사용하면 다른 메모리에 새로운 어레이를 하나 더 생성하기 때문이다.

이 때문에 실무에서 이 spread operator를 많이 사용한다.

join()

실무에서 정말 많이 쓰인다.

array 타입의 데이터를 하나의 스트링으로 묶을 때 사용한다.

기본형 : 변수명.join()

 

console.log(iveMembers);

console.log(iveMembers.join());
console.log(iveMembers.join('/'));
console.log(iveMembers.join(', '));

 

차례대로 맨 위는 iveMembers = ['안유진', '가을' ...] 으로 입력해둔 array의 값이다.

그리고 join()을 쓰니 리스트가 해제되고 스트링 타입으로 하나로 묶였다. join을 사용한 변수를 typeof 해보면 object가 아니라 string으로 나온다.

그리고 join의 소괄호에는 arguments를 사용할 수 있다. /나 , 콤마 뒤의 공백 등의 구분자를 사용 가능하다.

sort() 오름차순정렬 / reverse() 내림차순정렬

어레이의 값을 오름차순으로 재정렬한다. 값이 반환되지는 않음. 원래 array의 값 자체가 바뀌어 버림.

기본형 : 변수명.sort()
iveMembers.sort();
console.log(iveMembers);

원래는 안유진부터 어레이의 값으로 넣었는데 ㄱ - ㄹ - ㅇ- ㅈ 순으로 오름차순 정렬되었다.

반대로 reverse()를 쓰면 장원영부터 내림차순으로 정렬된다.

 

이 sort()를 사용하는 예시는 크게 아래의 3가지 경우다. 이해가 어렵다면 암기해야 하는 부분이다.

let numbers = [
    1,
    5,
    2,
    4,
    7,
    3,
    9
]

numbers.sort((a, b) => {
	return a > b ? 1 : -1;
});

console.log(numbers);

코드해석

쉽게 이야기해서 이것은 오름차순으로 정렬하는 메서드이다.

변수명.sort( (a, b) => { return a > b ? 1 : -1; } ) ;

오름차순 : 변수명.sort( (a, b) => { return a > b ? 1 : -1; } ) ;
내림차순 : 변수명.sort( (a, b) => { return a > b ? -1 : 1; } ) ;

 

이 메서드는 아래의 경우만 있다. 

  • a를 b보다 나중에 정렬하려면 (즉 뒤에 두려면) 0보다 큰 숫자를 반환
  • a를 b보다 먼저 정렬하려면 (즉 앞에 두려면) 0보다 작은 숫자를 반환
  • 원래 순서를 그대로 두려면 0을 반환

너무 어렵다. 위의 내용은 코드팩토리 강사님이 해주신 말을 그대로 적은 것이고 내가 이해한 방식대로 풀어보려고 했는데 잘 풀리지 않는다. 계속 공부할 예정이다.

 

현재까지 이해한 바는 다음과 같다.

일단 위의 기본형 자체가 하나의 공식처럼 외우면 될 것 같다. array를 오름차순으로 정렬하는 방법인 것이다.

굳이 1이나 -1이 아니라 100, -100을 써도 되지만 코드 가독성을 해치기 때문에 위의 식이 공식처럼 굳어진 것 같다.

 

나의 코드해석

나는 비전공자라... 유아틱하게 이해하여야 한다. 내가 이해한 내용은 아래와 같다.

let을 통해 numbers라는 변수의 값으로 [1, 5, 2, 4, 7, 3, 9]라는 어레이를 담았다.

numbers라는 변수에 sort()라는 메서드를 사용했다. sort() 메서드는 어레이의 값을 오름차순으로 정렬한다.

sort()에는 a, b 두 개의 파라미터를 만들었다.

그리고 a와 b를 비교해서 a가 b보다 크면 1, 아니면 -1을 반환한다.

sort()라는 비교 함수의 메서드는 양수를 반환하면 두 아규먼트의 위치를 바꾸고 음수면 그대로 둔다. 다른 비교함수에서는 이런 개념이 없다. 양수기만 하면 되고 음수기만 하면 되기에 100, -100으로 해도 되나 코드가독성 때문에 보통 1, -1로 설정한다.

sort() 메서드는 a와 b에 어레이의 값을 순서대로 넣어서 비교한다.

[1, 5, 2, 4,7, 3, 9]에서 먼저

1과 5를 비교한다. 1(a)가 5(b) 보다 크면 1, 작으면 -1인데 작으니 -1을 반환하고 음수이기 때문에 그대로 둔다.

그러면 지금까지는 배열이 [1, 5, 2, 4,7, 3, 9] 그대로다.

다시 5(a)와 2(b)를 비교한다. 5가 2보다 크니 1을 반환하고 양수이니 둘의 위치를 바꾼다.

그러면 지금까지는 배열이 [1, 2, 5, 4, 7, 3, 9]로 바뀌었다.

그리고 5와 4를 비교하고 5가 4보다 크니 1을 반환하고 위치를 서로 바꾼다.

그러면 지금까지는 배열이 [1, 2, 4, 5, 7, 3, 9]로 바뀌었다.

그리고 5와 7을 비교하니 -1을 반환하고 그대로 둔다.

그리고 7과 3을 비교하니 a가 더 커서 1을 반환하고 서로 위치를 바꾼다.

그러면 지금까지는 배열이 [1, 2, 4, 5, 3, 7, 9]로 바뀌었다.

그리고 7과 9를 비교하니 -1을 반환하고 그대로 둔다.

여기까지 한 사이클이 끝났다. 다시 1과 2를 비교하는 과정을 반복한다. 양수가 더이상 안 나와서 재정렬 할 필요가 없을 때까지 반복한다. 그러면 최종적으로 콘솔에는 작은 수부터 높은 수까지 오름차순으로 정렬된다.

 

 

 

[추가학습] 화살표 함수

=>와 같은 방법으로 표현하는 것인데, function 함수명 {함수바디}로 함수를 정의했던 것을 조금 더 간결하게 바꿔주는 기능이다.

function add(a, b) {
	return a + b;
}

// (a, b) 아규먼트를 받는 파라미터를 만들고, a, b에 숫자를 넣으면 a+b를 더해서 리턴해라.

예를들어 위와 같이 add라는 함수를 만들었다고 하면,

const add = (a, b) => {
	return a + b;
};

위와 같이 function이 아니라 const 등으로 함수를 설정할 수 있다.

이보다 더 축약된 형태로 작성하자면

const add = (a, b) => a + b;

위와 같이 중괄호 {}와 return까지 생략할 수 있다.

// 또 다른 예제

// 화살표 함수 적용 전
function square(number) {
    return number * number;
}

// 화살표 함수 적용
const square = (number) => { // function을 const로 바꾸고, 파라미터를 찢어서 =(파라미터)로 바꾼다. 그리고 => 화살표를 추가하고 실행할 함수 {}를 적는다.
    return number * number;
};

// 더 간단하게 변환
const square = (number) => number * number; // {} 중괄호와 return을 생략하고 한줄로 바꾼다.

// 모두 같은 함수다.

map()

map() 메서드는 배열을 순회하면서 각 요소에 대해 주어진 함수를 실행하고, 그 결과를 새로운 배열로 반환한다.

console.log(iveMembers.map((x) => x));
console.log(iveMembers.map((x) => `아이브: ${x}`));

예를들어 위에서 첫번째 함수는 x라는 파라미터를 받고 x 그 자체로 출력하라는 것이기에 어레이의 첫번째 값부터 순회해봤자 그대로 출력된다.

그런데 밑의 함수는 x에 백틱(템플릿 리터럴)을 넣어 특정 텍스트를 출력하는데 x 앞에 아이브가 붙어있다. 그래서 어레이의 앞부터 순회하면서 ${x} 값 앞에 아이브: 를 붙이며 콘솔에 출력하게 된다.

원래 값은 건드리지 않는다. (배열을 바꾸지 않는다.)

console.log(iveMembers.map((x) => {
  if( x === "장원영") {
    return `아이브 : ${x}`;
  } else {
    return x;
  }
}));

코드해석

iveMembers를 순회하면서 => {}를 실행해라.

무엇을 실행하냐면, if (만약에 x가 "장원영"일 때) true라면 {`아이브 : ${x}}라는 값을 리턴해라.

else 만약 아니라면 {x를 그냥 그대로 리턴해라}

(이 예제도 원래 iveMembers라는 어레이의 값을 변경하진 않는다.)

 

 

 

[추가학습] Template literals(템플릿 리터럴) (`` 백틱)

템플릿 리터럴은 코드의 가독성을 높여주는 방법이다.

아래 두 예시는 모두 같은 텍스트를 콘솔에 출력해주는데, 템플릿 리터럴을 사용하면 위 코드와 같이 복잡하게 쓰지 않아도 되어 가독성이 높아진다.

템플릿 리터럴 내에서는 ${} 구문을 사용해서 변수나 표현식을 직접 사용할 수 있다.

그리고 기존에는 멀티라인(줄바꿈하여 여러줄을 표현)을 표현할 때 \n  등을 계속 넣었어야 했으나, 템플릿 리터럴을 사용하면 우리가 입력하는 그대로 출력되기에 여러줄을 작성할 때는 그냥 엔터 누르고 작성하면 된다.

// 템플릿 리터럴 미사용
const name = "장원영";
const greeting = "안녕하세요," + name + "님!";

// 템플릿 리터럴 사용
const name = "장원영";
const name = `안녕하세요, ${name}님!`;

 

filter()

filter() 메서드는 배열(어레이)에서 원하는 값만 골라 새롭게 반환하는 메서드이다.

numbers = [1, 8, 7, 6, 3];

console.log(numbers.filter((x) => x % 2 === 0));

코드해석

numbers라는 어레이를 만들고 값으로 1, 8, 7, 6, 3을 할당했다.

filter() 메서드를 사용하여 x를 출력하도록 할 건데, x는 어레이의 값을 하나씩 받아와 2로 나누고 나머지가 0인 것들만 즉 짝수인 것들만 남기게 한다.

 

추가학습. var, let, const를 사용하지 않는 변수 선언

위의 코드 예제는 let numbers 등으로 선언한 것이 아니라 바로 numbers를 선언하였다. 만약 앞에서 이미 numbers를 var나 let으로 선언하였다면 그냥 number만 적는 것은 변수의 값을 바꾸는 코드이고 const는 물론 바뀌지 않는다.그런데 var 등으로 선언하지 않고 바로 변수명으로 선언해도 작동은 하는데, 이 경우에는 var로 선언한 것으로 간주한다.따라서 var에서 발생하는 호이스팅이 작동하기 때문에 의도치 않은 에러를 경험할 수 있어 가급적 let, const 등으로 선언해주는 것이 좋은 습관이다.

find()

filter()와 비슷한데, filter()는 해당 조건에 해당하는 모든 값을 어레이에 남기는 반면에 find()는 어레이의 처음부터 검사하다가 조건에 맞는 값이 있다면 그 값 하나만 출력하고 작업을 멈춘다. 

numbers = [1, 8, 7, 6, 3];

console.log(numbers.find((x) => x % 2 === 0));

즉 위와 같이 실행시키면 어레이 중 8이 이 조건에 가장 먼저 해당하니 콘솔에는 8만 출력된다.

뒤의 6까지는 진행하지 않는다.

findindex()

find()와 같은 기능이나, find()로 찾은 어레이 값을 반환하는 것이 아니라, 해당 값의 인덱스를 반환한다.

즉 위 find()에서 들었던 코드 예시를 findindex()로 바꿔서 보면 8이 위치한 인덱스값인 1을 출력한다.

reduce()

기본형 : 변수명.reduce((p, n) => p + n, 0);

reduce() 메서드는 배열의 각 요소에 대해 주어진 콜백 함수를 실행하고, 하나의 결과 값을 반환하는 메서드이다.

이 메서드는 배열을 순회하면서 각 요소를 처리하고, 최종 결과 값을 생성한다.

 

p, n은 reduce가 두 개의 파라미터를 받는다는 의미이다. 이 알파벳은 아무거나 써도 된다.

위의 설명을 풀어서 쓰자면 변수에 담긴 어레이에 대해서 콜백 함수를 실행하는데, 콜백 함수는 위 기본형에서 (p, n) => p + n까지를 의미한다.

즉 이 계산을 계속하면서 최종적으로 남는 값을 반환한다는 의미이다.

0은 누산기(Accumulator)라고 하는데 초기값을 의미한다.

 

코드해석

numbers에 1, 8, 7, 6, 3이라는 배열이 담겨있다고 가정한다.

뒤에 지정한 초기값인 0이 p에 입력된다.

배열의 첫번째 값인 1이 n에 입력된다.

화살표 밖으로 나가 0(p)과 1(n)을 더한다. 더한 값인 1이 반환된다.

이렇게 반환된 값이 다시 p에 입력된다.

그리고 어레이의 두번째 값인 8이 n에 들어간다.

다시 화살표 밖으로 나와 1과 8을 더해서 9가 반환된다.

이 9는 다시 p로 들어가고 n에 세번째 어레이 값인 7이 들어간다.

화살표 밖으로 나와 둘을 더하니 16이 된다.

이 16은 다시 p로 들어가고 n에는 어레이의 4번째 값 6이 들어간다.

더해서 22이 된다. 이 23은 다시 p로 들어가고 n에는 어레이의 마지막 값인 3이 들어간다.

둘을 더해서 25가 되었고, 여기서 작업은 끝나고 위 함수는 최종적으로 값 25가 된다.

 

 

출처 : https://www.youtube.com/watch?v=ZOVG7_41kJE&t=633s

 

 

댓글