Codestates/06.15 - 07.10

2020.06.19 [⭐️TIL] 배열로 함수열 프로그래밍하기

Hello, Big stranger 2020. 6. 20. 11:11

Lesson - 명령형 반복문을 함수형으로 작성하기 (forEach)

 

 자 여기에 특정 오브젝트들을 담고 있는 것이 있습니다.

앞으로 많이보게될 것입니다. 한사람에 정보가 쌓여있는 그것들이 목록으로 쌓여져있는 데이터베이스들을 말이죠.

 

let users = [

{ name : 'Tim', age : 40 },

{ name : 'Satya', age : 30 },

{ name : 'Sundar', age : 50 }

];

 

users // (3) 이되고 조회를 해보면 

 

0: {name: "Tim", age : 40}

1: {name : "Satya", age : 30}

2: {name : "Sundar", age : 50}

length : 3 들어가있는것을 볼수있다.

 

//console.log 로 이름을 출력하는 명령어를 볼것이다.

전체유저를 한바퀴 돌려야하니 잘알고있는 for 문을 이용한다.

 

for(let i = 0 ; i < users.length; i++){

cosole.log('Name: ' + users[i].name); - i 번쨰의 네임

}

Name : Tim

Name : Satya

Name : Sundar  나온다.

이것을 다른 방법으로 풀어봅시다. for문대신 함수형 프로그래밍으로 이용해서 풀어본다.

어렵고 낯선개념처럼느껴지지만 단순하다.

반복 실행할 액션을 따로 분리만 해주면 끝난다.

이름을 출력하는 것을(console.log) 함수로 printName 

function printName() {

console.log('Name: ' + users[i].name);

}

하지만 index로 통해서 배열의 몇번째 했다면 여기에서는 반복실행하는 대상이 있을것인데 반복적으로 있는 엘리먼트 ! 그게 이제 주체가 된다.

유저스에 들어있는게 뭐죠 ? 유저잖아요  이 가로안에있는것은 파라미터로 받는다. 그럼 팀, 사타야 사ㅏㄴ다 나온다.

 

function printName(user) {

console.log('Name: ' + users.name);

users.forEach(printName)  // forEach와함께 실행하는것이아닌 함수 그자체를 넣어주는것이다. 실행을 해보면

Name : Tim

Name : Satya

Name : Sundar

라는것을 알게된다.  

어때요 ? 낯설지만 조금 아시겠나요 ? // 좀더 알아야할것같아요

 

반복적인 실행하는 액션을 함수로 분리하고 파라미터로 반복되는 엘리먼트를 넣어준다. forEach

 

예를들어 함수로 만들어본다면 . 

즉 foo

let words = ['code', 'states']

function foo(word){

console.log(word);

}

words.forEach(foo)

code

states

여기에 하나씩 들어간다. 콘솔로그로 출력을 한다. 첫번째 파라미터는 반복적으로 들어가는 엘리먼특 ㅏ한버싞들어간다 즉 foo  word의 갯수만큼 실행되겠죠? foo를 변경시키면

 

 index 줄이면 idx 라고 해볼깡?

 

let words = ['code', 'states']

function foo(word, idx){

console.log(word, idx);

} - 첫번째 파라미터는 엘리멘터 두번째는 인덱스가 나온다 이름을 변경해도 상관없다. 작동은 똑같다. 파라미터 이름은 지어주지나름이다.

순서가 항상 엘리먼트 두번째는 인덱스 사실 세번째도 있다  오리지날이라는 해보면 원본배열 그냥 그대로가 세번쨰 파라미터에 들어가는것이 있다. 가장 많이 쓰는것은 첫번째를 많이쓴다.

 

code = 0

state = 2

 

Lesson - 배열의 형태 바꾸기 (map)

유저스 라는 배열에서 이름만 뽑아내고싶다고 과정해봅시다. 결과를 팀,사타야 선다르를 나오게 만들고 싶었다.

// ['tim', 'Satya', 'Sundar'

 

let users = [

{ name : 'Tim', age : 40 },

{ name : 'Satya', age : 30 },

{ name : 'Sundar', age : 50 }

];

 

let usernames = [];

for ( let i = 0; i <users.length; i++){ // i는 0번째 i는 유저스 만큼 반복해야하고요

usernaes.push(users[i].name); // 이름만 푸쉬해주면 되는거죠

}

// 3이라느 결과

usersnames

//(3) ["Tim","Satya","Sundar"]

자 이제 이거를 함수형 프로그래밍을 바꿔서 해볼께요

일단 우리가 반복적으로 실행했던것들이 push(users[i].name)인데 이것을 함수형으로 나타내주면 되는거니가

function pushName(user){

usernames.push(user.name);

}

usernames = [];

[]

user.forEach (pushName)

suernames

(3) ["Tim","Satya","Sundar"]

 

다른 방법 이있다 map라는 방법을 이용하는 법 

 

name 만 얻어내고 싶은것이다. 추출을 하는 함수를 따로 만들 수있다.

반복되는 유저를 파라미터로 넣어준다. 필요한게 네임이 필요하니까 네임을 작성함.

function getName(user){

return user.name;

}

getName({ name : 'Tim'', age : 40})

"Tim"

users.map(getName)

(3) ["Tim","Satya", "Sundar"] // 프로퍼티랑 함수를 다나오는

map은 보시다싶이직관적이징낳나요?  인풋이함수고 아웃푸시 새로운 어레이이다. 

보시면은 원래 어레이와 만들어진 어레이는 똑같고 형태가 다른것을 얻고자할때 유용하며 이뮤터블한 메소드다 원본어레이 그대로다

기존의 영향 끼치지않고 새로운 어레이를 만들 수 있다. 

 

Lesson - 조건에 따라 걸러내기(filter)

특정 조건에 있는 사람만 걸러내야한다.

 

let users = [

{ name : 'Tim', age : 40 },

{ name : 'Satya', age : 30 },

{ name : 'Sundar', age : 50 }

];

 

let searchResults = [];

for(let i = 0 ; i < users.length; i++){

// 40보다 나이가 많은 사람을 찾는다.

// 만으면 , searchResults 에 담는다.

if(users[i].age > 40){

searchResults.push(users[i])

}

}

1이나오며,

searchResults 하게되면 순다르만 나오게된다

[{...}]

0 : {name : "Sundar", age : 50}

length : 1

_proto_ : Array(0)

이번엔 함수형 프로그래밍을 사용하는것을 이용해보자 - filter method

filter 은 조건이 필요하잖아요 

조건이 뭐있냐 ? if(users[i].age > 40)

 

function moreThan40(user){

return user.age > 40;

}

그 후에 

users.filter(moreThan40);

값이 똑같이 나온다.

[{...}]

0 : {name : "Sundar", age : 50}

length : 1

_proto_ : Array(0)

이뮤터블이기떄문에 유저스에는 전혀 결과를 끼치지않느다

항상 새로운것을 만들떄마다리턴을 항상해준다.

 

s가들어간 사람을 리턴하고 싶다라고 하면

 

function includesS(user){

return user.name.indexOf('S') ! -- -1;

}

users.filter(includesS)

결고가 나온다

 

어떤 특정한 원본배열에서 조건을 이용해 추출해내고자 할때 요긴한 함수이다.

 

Lesson - 배열의 축소 (reduce)

 

- 배열에서 문자열로

- 배열에서 숫자로      

- 배열에서 객체로 

 

= 여러 개의 값이 담긴 배열이 줄여서(reduce) 최종적으로 하나의 값으로 만드는 과정

배열을 하나의 값으로 만드는 함수 : 리듀서 (reducer)

 

- 배열에서 객체로 

 

let user = [

{ name : 'Tim', city : 'Seoul' },

{ name : 'Satya', city : 'Seoul' },

{ name : 'Sundar', city : 'Los Angeles' }

];

 

experctedResult = 누적값

 

-> let experctedResult = {

'Seoul' : 2,

'Los Angeles' : 1

};

 

리듀서의 구성 요소 - 설명

 

누적값 - 배열의 요소를 하나하나 줄여나가면서 생기는 중간 과정 (결과)

현재 값 - 리듀서가 배열을 지나갈 때 만나는 배열의 요소 

초기 값 - 배열의 요소를 줄이기 전, 누적값의 초기 상태 

 

array.reduce( reducer, [initialValue]) Immutable

전달인자 : 리듀서, 초기값

- 리듀서 함수는 리턴값이 필요하며, 다음번 리듀서 호출 시 , 첫번째 파라미터로 전달됨

- 리턴값 : 리듀서가 마지막으로 리턴하는 값

 

function reducer(accumulator, value, index, array){

// TODO : accumulator 에 값을 누적시킨다.

return accumulator; // 새롭게 누적된 값

}

 

let population = {

'Seoul' : 0,

'Los Angeles' : 0

}; // 일단 아무도 살고있지않는다는가정을 넣었으니 0이라고 했다

 

user.reduce(reducer,population);

 

리듀서 함수의 파라미터 순서

- 순서대로 누적값(accumulator),현재 엘리먼트(value),인덱스(index),원본 배열(array)

 

Lesson - reduce 작동방식

 

mdn의 reduce() 작동 방식 을 꼭 읽어보시기 바랍니다.

reduce 메소드를 사용하는 코드에 대해 다음과 같이 설명하는 것을 볼 수 있습니다. 

예제

[0, 1, 2, 3, 4].reduce(function(accumulator, currentValue, currentIndex, array) { return accumulator + currentValue; });

호출 횟수accumulatorcurrentValue리턴 값

1번째 호출 0 1 1
2번째 호출 1 2 3
3번째 호출 3 3 6
4번째 호출 6 4 10

최종 리턴 값: 10

 

Lesson - reduce 실전 // 배열을 문자로 ( 매개변수 파악하기 )

 

let users = [

{ name : 'Tim', age : 40 }

{ name : 'Satya', age : 30 },

{ name : 'Sundar', age : 50 }

];

 

이름을 조합해서 쉼표와 공백으로 묶여져있는것을 만들라고 한다면 ? - 이런식으로 'Tim', 'Satya, 'Sundar'

' ' + user[0].name + ', ' + user[1].name + ', ' + users[2].name  // "Tim, Satya, Sunda"

절차적으로 해볼까요?

let resultString = ' '

for ( let i = 0; i<users.length; i++){

resultString = resultString + users[i].name + ', ' ;

}

"Tim, Satya, Sundar, "

resultstring

"Tim, Satya, Sundar, "

 

function 이름을 뭘로 ? 보시면은 이름을 쉼표와 공백을 합치고있는 함수이기 떄문에 joinName이라고 지을꼐요

 

function joinName (accumulator, currentValue){ // 누적값 누적시켜서 만들고 싶은 스트링(문자열)이잖아요 accumulator를 resultstr정도로 바꿔볼꼐요 currentvalue - 유저스를 한번한번 도는 유저들이 현재값이잖아요 그래서 user라고 바꿔줄수가 있겠다.

function joinName ( resultStr, user){ // ' ' + 'Tim' + ', ' // 'Tim, ' + ' Satya' + ', ' 이런식으로 resultStr이 계속 업데이트 되는거예요

이것을 리턴을 해줘야하니까  다음번 어큘러먼트로 쓸수있게

resultStr = resultStr + user.name + ', ';

return resultStr ;

}

 

user.reduce(joinName, ' ')  초깃값이 들어가는 빈스트링이 있어야한다.

"Tim, Satya, Sundar, "

 

 

function joinName(resultStr, user) { resultStr = resultStr + user.name + ', '; return resultStr; } let users = [ { name: 'Tim', age: 40 }, { name: 'Satya', age: 30 }, { name: 'Sundar', age: 50 } ]; users.reduce(joinName, '');

직접 따라해보세요

reduce의 콜백 함수 joinName은 총 몇번 실행되나요? 다음 표에 들어가는 값은 각각 무엇인가요?

호출 횟수resultStruser리턴 값

1번째 호출 ______ ______ ______
2번째 호출 ______ ______ ______
n번째 호출 ______ ______ ______

최종 리턴 값: ______

 

Lesson - reduce 실전 // 배열을 객체로 ( 매개변수 파악하기 )

 

let users = [

{ name : 'Tim', age : 40 }

{ name : 'Satya', age : 30 },

{ name : 'Sundar', age : 50 }

];

이름이 시작하는 알파벳으로 전화번호부를 만들어본다고 한다면 ?

최종적으로 얻고자 하는 자료형이 이것으로 보면된다.

{

T:[

{ name : 'Tim', age : 40 }

],

S : [

{ name : 'Satya', age : 30 },

{ name : 'Sundar', age : 50 }

]

}

{ T : Array(1), S : Array(2)} // 결과적으로 하나의 객체가 되는거죠. 어레이 벨류 로 각 들어가있는걸 볼수가있다.

하나하나 분해해본다면 어렵지않아요~ // 글쎄 ㅠ

 

let addressBook = {}: // 주소록이 목표인거니까 어드레스북이라는 오브젝트를 만들어 결국에는 우리의 목표는 오브젝트니까

addressBook['T']  = []; // 어드레스북에 배열이 있는거죠

addressBook['S'] = []; // 배열들어가게 ㅏㄴ드는거죠  

// 이름의 첫번째 글자로 , 주수록의 색인(key)을 만든다.

// 만일, key가 없으면, 해당 배열을 만들고, 사람을 추가한다.

// 만일, key가 있으면, 해당 배열에, 사람을 추가한다.

이것을 reducer로 만들어 불께요 참고하시라고 원본과 결과를 띠어놨다. 

 

function makeAddressBook(addressBook, user) { // (누적값, 한바퀴도는녀석넣음)
// 이름의 첫번째 글자로, 주소록의 색인(key)을 만든다.

let firstLetter = user.name[0];  // 최종결과물은 객체잖아요 어드레스 북은 { } 결과값으로 되어있을거고 키값이 있을수도 없을수도있잖아요 그래서

 

if(firstLetter in addressBook){ 

// 만일, key가 있으면, 해당 배열에, 사람을 추가한다

} else{

addressBook [firstLetter] = [];

// 만일, key가 없으면, 해당 배열을 만들고, 사람을 추가한다.

addressBook [firstLetter].push(user);

}

return addressBook;

}

 

//초기값 필요하죠 초기값 뭐예요 어드레스북의 빈 오브젝트잖아요 

 

users.reduce(makeAddressBook, {} )

하면 최종결과를 얻을수 가 있다.

 

users.reduce(makeAddressBook, {} )

{ T : Array(1), S : Array(2) }

S : Array(2)

0: {name : "Satya", age : 30}

1 : {name : "Sundar", age : 50}

length : 2

_proto_ : Array(0)

T : Array(1)

0 : {name : "Tim", age : 40}

length : 1

_proto_ : Array(0)

_proto_ : object

 

function makeAddressBook(addressBook, user) { let firstLetter = user.name[0]; if(firstLetter in addressBook) { addressBook[firstLetter].push(user); } else { addressBook[firstLetter] = []; addressBook[firstLetter].push(user); } return addressBook; } let users = [ { name: 'Tim', age: 40 }, { name: 'Satya', age: 30 }, { name: 'Sundar', age: 50 } ]; users.reduce(makeAddressBook, {});

직접 따라해보세요

reduce의 콜백 함수 makeAddressBook은 총 몇번 실행되나요? 다음 표에 들어가는 값은 각각 무엇인가요?

호출 횟수addressBookuser리턴 값

1번째 호출 ______ ______ ______
2번째 호출 ______ ______ ______
n번째 호출 ______ ______ ______

최종 리턴 값

{ T: [ { name: 'Tim', age: 40 } ], S: [ { name: 'Satya', age: 30 }, { name: 'Sundar', age: 50 } ] }

Slide : 배열다루기 

 

Slide : 숫자다루기