Higher Order Functions: Using Filter, Map and Reduce for More Maintainable Code - Lee-hyuna/33-js-concepts-kr GitHub Wiki

κ³ μ°¨ ν•¨μˆ˜ : μœ μ§€ λ³΄μˆ˜κ°€ μ‰¬μš΄ μ½”λ“œλ₯Ό μœ„ν•΄ Filter,Map 및 Reduce μ‚¬μš©

μž‘μ„±μž Guido Schmitz

κ³ μ°¨ ν•¨μˆ˜λŠ” μ½”λ“œλ₯Ό 보닀 μ„ μ–Έμ μœΌλ‘œ λ§Œλ“€μ–΄ μžλ°”μŠ€ν¬λ¦½νŠΈλ₯Ό κ°•ν™”ν•˜λŠ” 데 도움이 될 수 μžˆμŠ΅λ‹ˆλ‹€. 즉, 짧고 κ°„λ‹¨ν•˜κ²Œ 읽을 수 μžˆμŠ΅λ‹ˆλ‹€.

μ΄λŸ¬ν•œ κΈ°λŠ₯을 μ–Έμ œ μ–΄λ–»κ²Œ μ‚¬μš©ν•˜λŠ”μ§€ μ•Œκ³  μžˆλŠ” 것이 μ€‘μš”ν•©λ‹ˆλ‹€. μ½”λ“œλ₯Ό μ΄ν•΄ν•˜κ³  μœ μ§€ν•˜κΈ° μ‰½κ²Œ λ§Œλ“­λ‹ˆλ‹€.
λ˜ν•œ κΈ°λŠ₯을 μ„œλ‘œ μ‰½κ²Œ κ²°ν•© ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이것을 ꡬ성(composition)μ΄λΌκ³ ν•˜λ©° μ—¬κΈ°μ„œλŠ” μžμ„Ένžˆ μ„€λͺ…ν•˜μ§€ μ•Šκ² μŠ΅λ‹ˆλ‹€. 이 κΈ°μ‚¬μ—μ„œλŠ” μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œ κ°€μž₯ 많이 μ‚¬μš©λ˜λŠ” 3가지 κ³ μ°¨ ν•¨μˆ˜λ₯Ό λ‹€λ£° κ²ƒμž…λ‹ˆλ‹€. 이듀은 .filter(), .map() 및 .reduce()μž…λ‹ˆλ‹€.

Filter

18μ„Έ 이상인 μ‚¬λžŒλ“€μ„ κ±ΈλŸ¬λ‚Έ 리슀트 μ½”λ“œλ₯Ό μž‘μ„±ν•˜λŠ” 것을 μƒμƒν•΄λ΄…μ‹œλ‹€.
우리의 λ¦¬μŠ€νŠΈλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

const people = [ 
  { name: β€˜John Doe’, age: 16 }, 
  { name: β€˜Thomas Calls’, age: 19 }, 
  { name: β€˜Liam Smith’, age: 20 }, 
  { name: β€˜Jessy Pinkman’, age: 18 }
];

18μ„Έ 이상인 μ‚¬λžŒμ„ μ„ νƒν•˜λŠ” 1μ°¨ ν•¨μˆ˜μ˜ 예λ₯Ό μ‚΄νŽ΄ λ³΄κ² μŠ΅λ‹ˆλ‹€. ECMAScript ν‘œμ€€ λ˜λŠ” ES6의 일뢀인 ν™”μ‚΄ν‘œ ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ 짧게 μ“°κ³  μžˆμŠ΅λ‹ˆλ‹€. ν•¨μˆ˜λ₯Ό μ •μ˜ν•˜λŠ” 짧은 방법일 λΏμ΄λ―€λ‘œ κ΄„ν˜Έ, μ€‘κ΄„ν˜Έ 및 μ„Έλ―Έμ½œλ‘ λΏλ§Œ μ•„λ‹ˆλΌ function 타이핑 및 리턴을 κ±΄λ„ˆλ›Έ 수 μžˆμŠ΅λ‹ˆλ‹€.

const peopleAbove18 = (collection) => {  
  const results = [];   
  for (let i = 0; i < collection.length; i++) {    
    const person = collection[i];     
    if (person.age >= 18) {     
      results.push(person);   
    }  
  }
  return results;
};

이제 18μ„Έμ—μ„œ 20μ„Έ μ‚¬μ΄μ˜ λͺ¨λ“  μ‚¬λžŒλ“€μ„ μ„ νƒν•˜λ €λ©΄ μ–΄λ–»κ²Œν•΄μ•Όν•©λ‹ˆκΉŒ?
λ‹€λ₯Έ ν•¨μˆ˜λ₯Ό λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€.

const peopleBetween18And20 = (collection) => {  
  const results = [];   
  for (let i = 0; i < collection.length; i++) {    
    const person = collection[i];     
    if (person.age >= 18 && person.age <= 20) {      
      results.push(person);    
    }  
  }
  return results;
}

이미 λ§Žμ€ 반볡 μ½”λ“œλ₯Ό μ•Œκ³ μžˆμ„ 것 μž…λ‹ˆλ‹€. 보닀 일반적인 μ†”λ£¨μ…˜μœΌλ‘œ 좔상화 될 수 μžˆμŠ΅λ‹ˆλ‹€. 이 두 ν•¨μˆ˜μ—λŠ” 곡톡점이 μžˆμŠ΅λ‹ˆλ‹€. 그듀은 리슀트λ₯Ό λ°˜λ³΅ν•˜κ³  주어진 μ‘°κ±΄μ—μ„œ ν•„ν„°λ§ν•©λ‹ˆλ‹€.

"κ³ μ°¨ ν•¨μˆ˜λŠ” ν•˜λ‚˜ μ΄μƒμ˜ ν•¨μˆ˜λ₯Ό 인수둜 μ·¨ν•˜λŠ” ν•¨μˆ˜μž…λ‹ˆλ‹€." β€” Closurebridge

보닀 선언적 접근방식인 .filter()λ₯Ό μ‚¬μš©ν•˜μ—¬ 이전 ν•¨μˆ˜λ₯Ό κ°œμ„  ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

const peopleAbove18 = (collection) => {  
  return collection.filter((person) => person.age >= 18);
}

그게 λ‹€μž…λ‹ˆλ‹€! 이 κ³ μ°¨ ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ λ§Žμ€ μΆ”κ°€ μ½”λ“œλ₯Ό 쀄일 수 μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ μ½”λ“œλ₯Ό 더 잘 읽을 수 μžˆκ²Œν•©λ‹ˆλ‹€. ν•„ν„°λ§λ˜λŠ” 방식은 μ€‘μš”ν•˜μ§€ μ•ŠμœΌλ©° ν•„ν„°λ§λ§Œ ν•˜λ©΄ λ©λ‹ˆλ‹€. 이 κ²Œμ‹œκΈ€ λ’·λΆ€λΆ„μ—μ„œ ν•¨μˆ˜λ₯Ό κ²°ν•©ν•˜λŠ” 방법에 λŒ€ν•΄ μ‚΄νŽ΄ λ³΄κ² μŠ΅λ‹ˆλ‹€.

Map

컀피λ₯Ό λ§ˆμ‹œλŠ” 것을 μ’‹μ•„ν•˜λŠ”μ§€ μ•Œλ €μ£ΌλŠ” λ™μΌν•œ μ‚¬λžŒ λ¦¬μŠ€νŠΈμ™€ μ΄λ¦„μ˜ 배열을 λ΄…μ‹œλ‹€.

const coffeeLovers = [β€˜John Doe’, β€˜Liam Smith’, β€˜Jessy Pinkman’];

λͺ…λ Ή 방식은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€:

const addCoffeeLoverValue = (collection) => {  
  const results = [];   
  for (let i = 0; i < collection.length; i++) {    
    const person = collection[i];
    if (coffeeLovers.includes(person.name)) {      person.coffeeLover = true;    
    } else {      
      person.coffeeLover = false;   
    }    
    results.push(person);  
  } 
  return results;
};

.map()을 μ‚¬μš©ν•˜μ—¬ 더 μ„ μ–Έμ μœΌλ‘œ λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€.

const incrementAge = (collection) => {  
  return collection.map((person) => {    
    person.coffeeLover = coffeeLovers.includes(person.name);     return person;  
  });
};

.map()은 κ³ μ°¨ ν•¨μˆ˜μž…λ‹ˆλ‹€. ν•¨μˆ˜κ°€ 인수둜 전달 될 수 μžˆμŠ΅λ‹ˆλ‹€.

Reduce

μ–Έμ œ, μ–΄λ–»κ²Œ μ‚¬μš©ν•˜λŠ”μ§€ μ•Œλ•Œ 이 ν•¨μˆ˜λ₯Ό λ§ˆμŒμ— λ“€μ–΄ ν•  κ²ƒμž…λ‹ˆλ‹€. .reduce()의 멋진 점은 μœ„ λŒ€λΆ€λΆ„μ˜ ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ λ§Œλ“€ 수 μžˆλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.

λ¨Όμ € κ°„λ‹¨ν•œ 예λ₯Ό λ“€μ–΄ λ³΄κ² μŠ΅λ‹ˆλ‹€. μš°λ¦¬λŠ” λͺ¨λ“  μ‚¬λžŒλ“€μ˜ λ‚˜μ΄λ₯Ό ν•©μΉ˜κ³  μ‹ΆμŠ΅λ‹ˆλ‹€. λ‹€μ‹œ ν•œ 번 λͺ…λ Ή 방식을 μ‚¬μš©ν•˜μ—¬ 이 μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” 방법을 μ‚΄νŽ΄ λ³΄κ² μŠ΅λ‹ˆλ‹€. 기본적으둜 μ»¬λ ‰μ…˜(μˆ˜μ§‘)을 λ°˜λ³΅ν•˜κ³  연령에 따라 λ³€μˆ˜λ₯Ό μ¦κ°€μ‹œν‚΅λ‹ˆλ‹€.

const sumAge = (collection) => {  
  let num = 0;   
  collection.forEach((person) => {    
    num += person.age;  
  });   
  return num;
}

그리고 .reduce()λ₯Ό μ‚¬μš©ν•˜λŠ” 선언적 μ ‘κ·Ό 방식.

const sumAge = (collection) => collection.reduce((sum, person) => { return sum + person.age;
}, 0);

μš°λ¦¬λŠ” .reduce()λ₯Ό μ‚¬μš©ν•˜μ—¬ .map() 및 .filter()의 κ΅¬ν˜„μ„ λ§Œλ“€ μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

const map = (collection, fn) => { 
  return collection.reduce((acc, item) => {    
    return acc.concat(fn(item));  
  }, []);
}
const filter = (collection, fn) => {  
  return collection.reduce((acc, item) => {    
    if (fn(item)) {      
      return acc.concat(item);    
    }     
    return acc;  
  }, []);
}

μ²˜μŒμ—λŠ” μ΄ν•΄ν•˜κΈ° μ–΄λ €μšΈ 수 μžˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ .reduce()λŠ” 기본적으둜 μ»¬λ ‰μ…˜κ³Ό 초기 값을 가진 λ³€μˆ˜λ‘œ μ‹œμž‘ν•©λ‹ˆλ‹€. 그런 λ‹€μŒ μ»¬λ ‰μ…˜μ„ λ°˜λ³΅ν•˜κ³  값을 λ³€μˆ˜μ— λ§λΆ™μ΄κ±°λ‚˜(λ˜λŠ” μΆ”κ°€) ν•©λ‹ˆλ‹€.

Combining map, filter and reduce

μ΄λŸ¬ν•œ ν•¨μˆ˜κ°€ μ‘΄μž¬ν•œλ‹€λŠ” 점은 ν›Œλ₯­ν•©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ 쒋은 점은 μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ Array ν”„λ‘œν†  νƒ€μž…μ— μ‘΄μž¬ν•œλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. 즉,이 ν•¨μˆ˜λ“€μ„ ν•¨κ»˜ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€! 이λ₯Ό 톡해 μž¬μ‚¬μš© κ°€λŠ₯ν•œ ν•¨μˆ˜λ₯Ό μ‰½κ²Œ λ§Œλ“€κ³  νŠΉμ • ν•¨μˆ˜λ₯Ό μž‘μ„±ν•˜λŠ” 데 ν•„μš”ν•œ μ½”λ“œμ˜ 양을 쀄일 수 μžˆμŠ΅λ‹ˆλ‹€.

κ·Έλž˜μ„œ μš°λ¦¬λŠ” 18μ„Έ μ΄ν•˜μ˜ μ‚¬λžŒλ“€μ„ κ±ΈλŸ¬λ‚΄κΈ° μœ„ν•΄ .filter()λ₯Ό μ‚¬μš©ν•˜λŠ” 것에 λŒ€ν•΄ μ΄μ•ΌκΈ°ν–ˆμŠ΅λ‹ˆλ‹€. coffeeLover property을 μΆ”κ°€ν•˜λŠ” .map()κ³Ό reduce()λ₯Ό ν•©μ³μ„œ λ§ˆμΉ¨λ‚΄ λͺ¨λ“  μ‚¬λžŒμ˜ λ‚˜μ΄λ₯Ό ν•©ν•œ 합계λ₯Ό λ§Œλ“­λ‹ˆλ‹€. μ‹€μ œλ‘œ 이 μ„Έ 단계λ₯Ό κ²°ν•©ν•œ μ½”λ“œλ₯Ό μž‘μ„±ν•΄ λ΄…μ‹œλ‹€.

const people = [ 
  { name: β€˜John Doe’, age: 16 }, 
  { name: β€˜Thomas Calls’, age: 19 }, 
  { name: β€˜Liam Smith’, age: 20 },
  { name: β€˜Jessy Pinkman’, age: 18 }
];
const coffeeLovers = [β€˜John Doe’, β€˜Liam Smith’, β€˜Jessy Pinkman’];
const ageAbove18 = (person) => person.age >= 18;
const addCoffeeLoverProperty = (person) => { 
  person.coffeeLover = coffeeLovers.includes(person.name);  
  return person;
}
const ageReducer = (sum, person) => { return sum + person.age;}, 0);
const coffeeLoversAbove18 = people.filter(ageAbove18).map(addCoffeeLoverProperty);
const totalAgeOfCoffeeLoversAbove18 = coffeeLoversAbove18.reduce(ageReducer);
const totalAge = people.reduce(ageReducer);

만일 의무적인 λ°©μ‹μœΌλ‘œ μˆ˜ν–‰ν•˜λ©΄ λ§Žμ€ 반볡 μ½”λ“œλ₯Ό μž‘μ„±ν•˜κ²Œλ©λ‹ˆλ‹€.

.map(), .reduce(), .filter()둜 ν•¨μˆ˜λ₯Ό λ§Œλ“œλŠ” 사고방식은
당신이 μ“Έ μ½”λ“œμ˜ ν’ˆμ§ˆμ„ ν–₯μƒμ‹œν‚¬ κ²ƒμž…λ‹ˆλ‹€.
ν•˜μ§€λ§Œ 가독성도 많이 λ”ν•©λ‹ˆλ‹€.
ν•¨μˆ˜ μ•ˆμ—μ„œ 무슨 일이 μΌμ–΄λ‚˜κ³  μžˆλŠ”μ§€ 생각할 ν•„μš”λ„ μ—†μŠ΅λ‹ˆλ‹€.
μ΄ν•΄ν•˜κΈ° μ‰½μŠ΅λ‹ˆλ‹€.