Javascript_30_04

Derek·2020년 12월 16일
0

javascript_30

목록 보기
5/31
post-thumbnail

안녕하세요!

Derek 입니다! 😄

오늘은 영하 8도였네요.. 진짜 어마무시한 추위인것 같아요 요즘! 다들 감기 조심하세요..ㅜ 🥶

오늘은 Javascript 30 의 4번째 주제를 가지고 포스팅 해보려고 해요!

Day04 project는 이전의 게시물 보다는 약간 정적이고 눈에 보이는 것이 아니라 지루할 수도 있지만, 누가봐도 너무 유용하게 쓰일 것이라..! 잘 정리해보겠습니다 🙃




04. Array Cardio Day 1

목표

배열에 관한 여러가지 연산 (filter, map, sort, reduce) 에 대해 연습해본다.

먼저, 이번 프로젝트에서는 크게 2가지 배열을 먼저 제공 받았습니다.
배열 내용은 다음과 같아요.

    const inventors = [
      { first: 'Albert', last: 'Einstein', year: 1879, passed: 1955 },
      { first: 'Isaac', last: 'Newton', year: 1643, passed: 1727 },
      { first: 'Galileo', last: 'Galilei', year: 1564, passed: 1642 },
      { first: 'Marie', last: 'Curie', year: 1867, passed: 1934 },
      { first: 'Johannes', last: 'Kepler', year: 1571, passed: 1630 },
      { first: 'Nicolaus', last: 'Copernicus', year: 1473, passed: 1543 },
      { first: 'Max', last: 'Planck', year: 1858, passed: 1947 },
      { first: 'Katherine', last: 'Blodgett', year: 1898, passed: 1979 },
      { first: 'Ada', last: 'Lovelace', year: 1815, passed: 1852 },
      { first: 'Sarah E.', last: 'Goode', year: 1855, passed: 1905 },
      { first: 'Lise', last: 'Meitner', year: 1878, passed: 1968 },
      { first: 'Hanna', last: 'Hammarström', year: 1829, passed: 1909 }
    ];

    const people = [
      'Bernhard, Sandra', 'Bethea, Erin', 'Becker, Carl', 'Bentsen, Lloyd', 'Beckett, Samuel', 'Blake, William', 'Berger, Ric', 'Beddoes, Mick', 'Beethoven, Ludwig',
      'Belloc, Hilaire', 'Begin, Menachem', 'Bellow, Saul', 'Benchley, Robert', 'Blair, Robert', 'Benenson, Peter', 'Benjamin, Walter', 'Berlin, Irving',
      'Benn, Tony', 'Benson, Leana', 'Bent, Silas', 'Berle, Milton', 'Berry, Halle', 'Biko, Steve', 'Beck, Glenn', 'Bergman, Ingmar', 'Black, Elk', 'Berio, Luciano',
      'Berne, Eric', 'Berra, Yogi', 'Berry, Wendell', 'Bevan, Aneurin', 'Ben-Gurion, David', 'Bevel, Ken', 'Biden, Joseph', 'Bennington, Chester', 'Bierce, Ambrose',
      'Billings, Josh', 'Birrell, Augustine', 'Blair, Tony', 'Beecher, Henry', 'Biondo, Frank'
    ];

약간 복잡해보이지만, 크게 보면 inventors 배열과 people 배열 두 개를 가지고 이런저런 함수를 써보는 시간을 가져봤어요!

하나하나 문제로 나왔던 부분을 차례로 설명드릴게요.


01. Filter the list of inventors for those who were born in the 1500's

첫번째 질문은 1500년대에 태어난 (year 가 1500이상 1600미만) 사람을 필터링 하는 질문이였습니다.

MDN 에 따르면, filter 의 정의는 아래와 같습니다.

filter() 메서드는 주어진 함수의 테스트를 통과하는 모든 요소를 모아 새로운 배열로 반환합니다

또한, 기본적인 사용시 골격은

let results = arr.filter(function(item, index, array) {
  // 조건을 충족하는 요소는 results에 순차적으로 더해집니다.
  // 조건을 충족하는 요소가 하나도 없으면 빈 배열이 반환됩니다.
});

filter 의 특징은 배열을 반환한다는 점인 것 같아요!

더 세부적인 예시를 들어볼게요.

let users = [
  {id: 1, name: "John"},
  {id: 2, name: "Pete"},
  {id: 3, name: "Mary"}
];

// 앞쪽 사용자 두 명을 반환합니다.
let someUsers = users.filter(item => item.id < 3);

alert(someUsers.length); // 2

objects가 있는 users 배열에 화살표 함수 item => item.id < 3 를 사용하여 각각 원소의 id 값이 3 미만인 객체들을 필터링 하는 모습입니다.

따라서 someUsers 에는 id 가 1, 2 인 객체가 들어간 object 배열을 받게됩니다.


이번 문제에서는 저는 이렇게 작성했습니다.

Derek 구현코드

    const elder = inventors.filter(person => person.year >= 1500 && person.year < 1600);

간단하게 해결했습니다! 😄 filter 함수를 사용해 각각 객체를 person 으로 보고 각 객체의 year 속성에 접근했습니다.


02. Give us an array of the inventors first and last names

다음 질문! inverntors 배열에서 firstNamelastName 을 리턴하는 것이 요구사항이였습니다.

이는 새로운 배열을 만드는 map 메소드를 사용했는데요, 그 정의 및 예제를 잠깐살펴볼게요.

MDN 에 따르면, map 의 정의는 아래와 같습니다.

map() 메서드는 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환합니다.

주목해야 할 점은 새로운 배열을 반환하는 점인데요, 정확한 예시를 보여드릴게요.

const array1 = [1, 4, 9, 16];

// pass a function to map
const map1 = array1.map(x => x * 2);

console.log(map1);
// expected output: Array [2, 8, 18, 32]

기존에 존재하는 array1 이라는 배열을 기반으로 map1 배열을 새로 생성했습니다!
대신, array1 배열의 모든 원소에 2씩 증가시켜 새로운 배열을 생성한 모습을 확인 할 수 있어요.

Derek 구현코드

    const inventorsFirst = inventors.map(x => x.first);
    const inventorsLast = inventors.map(x => x.last);

간단합니다! 익명함수를 화살표로 사용하여 inventorsFirstinventorsLast 배열에 각각 first 와 `last 를 저장했습니다. 😺


3. Sort the inventors by birthdate, oldest to youngest

다음 질문은 sort 항목이였습니다..!

사실 이게.. 진짜 빠삭하게 이해가 가질 않아서.. 일단은 제가 이해한 내용을 기반으로 작성해보겠습니다.

MDN 에 따르면, sort 의 정의는 아래와 같습니다.

sort() 메서드는 배열의 요소를 적절한 위치에 정렬한 후 그 배열을 반환합니다. 정렬은 stable sort가 아닐 수 있습니다. 기본 정렬 순서는 문자열의 유니코드 코드 포인트를 따릅니다.

가장 주목해야할 부분은, 문자열의 유니코드 코드 포인트 인것 같아요! 즉, 기본적인 소팅 순서는 문자열의 크기라는 뜻이죠!

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

const array1 = [1, 30, 4, 21, 100000];
array1.sort();
console.log(array1);
// expected output: Array [1, 100000, 21, 30, 4]

해당 웹사이트에 나와있는 예시입니다. months 는 기본적으로 문자열들이 들어가 있고, 이를 소팅하면 문자열 순서대로 소팅이 됨을 알 수 있어요.

하지만 array1 를 보시면 흔히 숫자 소팅하듯이 결과가 1, 4, 21, 30, 10000 가 아닌, 문자열대로 소팅 한 것을 확인 하실 수 있습니다.

이런 소팅은 c++ 에서 벡터를 소팅할때 조건함수를 쓰듯이 조건을 걸수가 있어요.
바로 비교함수를 사용하면 됩니다.

비교함수

이 내용은 jakeSeo.velog를 많이 참조했습니다.

sort 함수의 기본 문법은 arr.sort([compareFunction]) 입니다. 여기서 우리가 정의해줘야 하는 것은 [compareFunction] 부분입니다.

[compareFunction]sort 함수의 콜백함수firstElsecondEl이란 인자가 자동으로 들어갑니다. 이 콜백함수의 작성을 생략하면 이전에 설명했듯 문자열로 바뀐 뒤 UTF-16의 코드 유닛 값을 기준으로 정렬이 수행됩니다.

sort() 함수의 괄호 안에 2개의 변수를 사용하는 익명함수를 쓰면, 커스터마이징이 되어, 사용자가 원하는 소팅을 할 수 있다는 것이에요.

compareFunction 은 다음과 같은 특징이 있다고 합니다.

[compareFunction]을 작성할 때는 어떤 값을 반환하는지가 중요 합니다. 숫자 값을 반환해야 하는데 총 3가지 경우로 나눌 수 있습니다.

  • 0보다 크다
  • 0이다
  • 0보다 작다

0을 기준으로 3가지 케이스로 나뉩니다.

매개변수로 a, b를 받았고 반환 값이 0보다 큰 경우에는 만일 [a, b]의 값이 들어왔다면, 그대로 [a, b]가 됩니다. a가 먼저옵니다.
매개변수로 a, b를 받았고 반환 값이 0인 경우에는 만일 [a, b]의 값이 들어왔다면, 그대로 [a, b]가 됩니다. ab의 위치를 그대로 둡니다.
매개변수로 a, b를 받았고 반환 값이 0보다 작은 경우에 [a, b]의 값이 들어왔다면, b가 먼저 오게 됩니다. [b, a] 가 되는 겁니다.
즉, 음수가 리턴되면 순서를 바꾸어라!

그런데 말입니다. (김상중씨)

var numbers = [4, 2, 5, 1, 3];
numbers.sort(function(a, b) {
  return a - b;
});
console.log(numbers);
// [1, 2, 3, 4, 5]

위와 같은 코드가 있으면, sort 에 있는 functiona, b 가 차례로 들어가는데, 저는 처음에 당연히 첫 루프에 a = 4, b = 2 인 쌍으로 들어가는줄 알았습니다.

???? 근데 그게 아니래요! ab 의 순서는 바뀌어 들어가서 판단이 된다고 하더라구요..?

즉, anext, bprevious 로 생각하면 된다고 .. 하더라구요. (왜? 진짜 1도 이해안감)

그렇다면 위의 코드를 다시 볼게요.

var numbers = [4, 2, 5, 1, 3];
numbers.sort(function(a, b) {
  return a - b;
});
console.log(numbers);
// [1, 2, 3, 4, 5]

첫 루프를, 생각해봅시다. 첫 루프. 천천히.
anext 이니까, 2 가 들어와요. 그리고,b 는, prev 니까 4 가 들어오네요.
a - b 값은, 그러면, 2 - 4 이니까, -2 네요!

앗 그러면 음수네요?! 그럼 바꿔야겠네요? [4, 2] -> [2, 4] ...

그렇게, 쭉쭉 가다보면 결국엔 오름차순이 되겠죠 뭐 더 하나하나 해보고 싶지도 않아요..

--> 이 부분 관련해서 왜 순서가 바뀌어야하는지 아시는 분은 댓글.. 부탁드립니다 😭

정리하자면,

sort 함수의 핵심은 비교함수를 작성하는 것이고, 비교함수에서 a(next)b(prev)가 들어오고 무언가 바꾸고 싶을 때 -1을 리턴하는 것! 입니다.

이 정도가 맞는것 같아요.

많이 돌아왔네요..! 그래서 이번 소문제 문제는 연세가 많으신 순서대로 sort() 을 하는 문제였는데,

이거는 2개 방법으로 해보았어요.

const ordered = inventors.sort(function(a, b){
      if(a.year > b.year){
        return 1;
      }
        else{
          return -1;
        }
      }

anext 객체, bprevious 객체인거 생각하고, 정리하면,
만약 다음 객체의 year 가 크면, 즉 ayearbyear 보다 크면,
그대로 순서를 냅두자! (if(a.year > b.year){ return 1 };)

아니야! 이전 객체의 year 가 더 커! byearayear 보다 크네?!
그럼 순서를 바꿔야 해! (else{ return -1; })


제가 이해가 어려워서.. 저런 형식으로 설명 드렸어요..

다른 방법으로는,

const sortInventors = inventors.sort((a, b) => a.year - b.year );

이렇게, 한줄로도 쓸 수가 있습니다. 이는 위에와 별 다른게 없을것 같아요.

a.year - b.year 했는데(다음거 빼기 이전거), 양수 -> 그대로 / 음수 -> 바꿔

이정도로.. 설명이 가능할 것 같습니다. 😅


4. How many years did all the inventors live all together?

다음 질문입니다! 모든 사람의 수명을 더하라는, 누적시키는 기능을 물어보는 질문이였어욥.

reduce 메소드를 쓰라고 했는데, MDN 에 따르면, reduce 의 정의는 아래와 같습니다.

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

기본형은 이렇게 생겼어요.

let value = arr.reduce(function(accumulator, item, index, array) {
  // ...
}, [initial]);
  • accumulator – 이전 함수 호출의 결과. initial은 함수 최초 호출 시 사용되는 초깃값을 나타냄(옵션)
  • item – 현재 배열 요소
  • index – 요소의 위치
  • array – 배열

약간 복잡해 보이는데, 예를 들어볼게요.

let arr = [1, 2, 3, 4, 5];

let result = arr.reduce((sum, current) => sum + current, 0);

alert(result); // 15

여기서, sum은, 누적한 값을 저장시키는 친구에요! 그 sum이라는 변수는, 두번째 줄 맨 마지막인, 0 으로 초기화가 됩니다.

current 는 현재 배열 요소를 뜻합니다. forEach 에서 배열요소를 생각하면 될것 같아요.

자세한 로직 방향은 아래와 같습니다.

  1. 함수 최초 호출 시, reduce의 마지막 인수인 0(초깃값)sum에 할당됩니다. current 엔 배열의 첫 번째 요소인 1이 할당됩니다. 따라서 함수의 결과는 1이 됩니다.
  2. 두 번째 호출 시, sum = 1 이고 여기에 배열의 두 번째 요소(2)가 더해지므로 결과는 3이 됩니다.
  3. 세 번째 호출 시, sum = 3 이고 여기에 배열의 다음 요소가 더해집니다. 이런 과정이 계속 이어집니다.

(출처: javascript.info)


그래서, 이번 소문제는 모든 사람의 수명을 더하라고 했었는데요, 이는
    const sum = inventors.reduce((acc, cur) => acc + (cur.passed - cur.year), 0);

이런식으로 만들어보았어요.

0으로 초기화 시킨 acccur.passed - cur.year 값을 더하면, 한 객체에 대한 수명이 계산되어, 이를 acc 에 누적시켰습니다 :)




글이 매우 길었네요!

배열의 기본적인 메소드들 filter, map, sort, reduce 기능을 살펴보았습니다.

틀린내용이나 수정할 내용이 있다면 언제든지 피드백 부탁드립니다!
감사합니다!🤗

profile
Whereof one cannot speak, thereof one must be silent.

0개의 댓글