이제 하루 남았다,, 그동안 엄청 열심히는 아니지만 코딩테스트 문제에 익숙해지고 꾸준히 푸는 습관을 기르기 위해 바쁘거나 힘들지 않은 이상 최대한 매일 풀기 위해 노력했다. 그동안 풀었다는 게 눈에 보이니 확실히 효과가 커지는 것 같다. 솔직히 모두 답지없이 스스로 풀지 않았기에 조금만 뿌듯 ㅜㅜ 이제부터 레벨을 올려서 풀어보고 싶다. 내일이 마지막이니 최선을 다해보자!
Day 24
수학, 시뮬레이션, 문자열, 조건문, 반복문
문제 설명
프로그래머스 치킨은 치킨을 시켜먹으면 한 마리당 쿠폰을 한 장 발급합니다. 쿠폰을 열 장 모으면 치킨을 한 마리 서비스로 받을 수 있고, 서비스 치킨에도 쿠폰이 발급됩니다. 시켜먹은 치킨의 수 chicken이 매개변수로 주어질 때 받을 수 있는 최대 서비스 치킨의 수를 return하도록 solution 함수를 완성해주세요.
function solution(chicken) {
let answer = 0;
while(chicken >= 10){
answer += Math.floor(chicken / 10);
chicken = chicken % 10 + Math.floor(chicken / 10);
}
return answer;
}
문제 설명
이진수를 의미하는 두 개의 문자열 bin1과 bin2가 매개변수로 주어질 때, 두 이진수의 합을 return하도록 solution 함수를 완성해주세요.
function solution(bin1, bin2) {
return (parseInt(bin1, 2) + parseInt(bin2, 2)).toString(2);
}
// 다른 사람의 풀이
function solution(bin1, bin2) {
let temp = Number(bin1) + Number(bin2);
temp = [...temp.toString()].reverse().map((v) => +v);
for (let i = temp.length; i < 11; i++) {
temp.push(0);
}
for (let i = 0; i < temp.length; i++) {
if (temp[i] === 2) {
temp[i] = 0;
temp[i + 1]++;
} else if (temp[i] === 3) {
temp[i] = 1;
temp[i + 1]++;
}
}
return Number(temp.reverse().join("")).toString();
}
console.log(parseInt("10")); // 10
console.log(parseInt("10", 2)); // 2
console.log(parseInt("25", 2)); // NaN
let baseTenInt = 10;
console.log(baseTenInt.toString(2)); // "1010"이 출력됨
문제 설명
문자열 before와 after가 매개변수로 주어질 때, before의 순서를 바꾸어 after를 만들 수 있으면 1을, 만들 수 없으면 0을 return 하도록 solution 함수를 완성해보세요.
function solution(before, after) {
before = [...before].sort();
after = [...after].sort();
return before.filter((a, i) => a === after[i]).length === after.length ? 1 : 0;
}
문제 설명
1부터 13까지의 수에서, 1은 1, 10, 11, 12, 13 이렇게 총 6번 등장합니다. 정수 i, j, k가 매개변수로 주어질 때, i부터 j까지 k가 몇 번 등장하는지 return 하도록 solution 함수를 완성해주세요.
function solution(i, j, k) {
let answer = "";
for(let n=i; n<=j; n++) answer += String(n);
return [...answer].filter(s => s.includes(k)).length;
}
// 다른 사람의 풀이
function solution(i, j, k) {
let a ='';
for(i;i<=j;i++){
a += i;
}
return a.split(k).length-1;
}
두 개의 state 변수가 항상 함께 변경되는 경우엔 하나의 state 변수로 통합하는 것이 좋음
const [x, setX] = useState(0);
const [y, setY] = useState(0);
// =>
const [position, setPosition] = useState({ x: 0, y: 0 });
데이터를 객체나 배열로 그룹화하는 또 다른 경우는 필요한 state의 조각 수를 모를 때. 예를 들어, 사용자가 사용자 정의 필드를 추가할 수 있는 양식이 있을 때 유용함.
“불가능한” state의 설정을 허용하고 있음
setIsSent
와 setIsSending
중 어느 하나만 호출하면 동시에 true가 되는 상황이 발생status
는 typeing
(초기), sending
, sent
가 될 수 있음import { useState } from 'react';
export default function FeedbackForm() {
// before
// const [text, setText] = useState('');
// const [isSending, setIsSending] = useState(false);
// const [isSent, setIsSent] = useState(false);
// async function handleSubmit(e) {
// e.preventDefault();
// setIsSending(true);
// await sendMessage(text);
// setIsSending(false);
// setIsSent(true);
// }
const [text, setText] = useState('');
const [status, setStatus] = useState('typing');
async function handleSubmit(e) {
e.preventDefault();
setStatus('sending');
await sendMessage(text);
setStatus('sent');
}
const isSending = status === 'sending';
const isSent = status === 'sent';
if (isSent) {
return <h1>Thanks for feedback!</h1>
}
return (
<form onSubmit={handleSubmit}>
<p>How was your stay at The Prancing Pony?</p>
<textarea
disabled={isSending}
value={text}
onChange={e => setText(e.target.value)}
/>
<br />
<button
disabled={isSending}
type="submit"
>
Send
</button>
{isSending && <p>Sending...</p>}
</form>
);
}
// Pretend to send a message.
function sendMessage(text) {
return new Promise(resolve => {
setTimeout(resolve, 2000);
});
}
렌더링 중에 컴포넌트의 props나 기존 state 변수에서 일부 정보를 계산할 수 있는 경우 해당 정보를 컴포넌트의 state에 넣지 않아야 함.
fullName
은 불필요함. 렌더링 중 언제든 firstName
과 lastName
에서 계산할 수 있으므로 state에서 제거!// before
export default function Form() {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [fullName, setFullName] = useState('');
function handleFirstNameChange(e) {
setFirstName(e.target.value);
setFullName(e.target.value + ' ' + lastName);
}
function handleLastNameChange(e) {
setLastName(e.target.value);
setFullName(firstName + ' ' + e.target.value);
}
...
}
// after
export default function Form() {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const fullName = firstName + ' ' + lastName;
function handleFirstNameChange(e) {
setFirstName(e.target.value);
}
function handleLastNameChange(e) {
setLastName(e.target.value);
}
...
}
다음 코드는 중복 state의 일반적인 예시:
function Message({ messageColor }) {
const [color, setColor] = useState(messageColor);
문제는 부모 컴포넌트가 나중에 다른 messageColor
값(예: blue
대신 red
)을 전달하면 color
state 변수가 업데이트되지 않는다는 것! state는 첫 번째 렌더링 중에만 초기화됨.
대신 코드에서 messageColor
prop을 직접 사용하기. 더 짧은 이름을 지정하려면 상수를 사용. 이렇게 하면 부모 컴포넌트에서 전달된 prop과 동기화되지 않음.
function Message({ messageColor }) {
const color = messageColor;
props를 state로 ‘미러링’하는 것은 특정 prop에 대한 모든 업데이트를 무시하려는 경우에만 의미있음. 관례에 따라 prop 이름을 initial
또는 default
로 시작해 새 값이 무시됨을 명확히 하기.
function Message({ initialColor }) {
// The `color` state variable holds the *first* value of `initialColor`.
// Further changes to the `initialColor` prop are ignored.
const [color, setColor] = useState(initialColor);
import { useState } from 'react';
const initialItems = [
{ title: 'pretzels', id: 0 },
{ title: 'crispy seaweed', id: 1 },
{ title: 'granola bar', id: 2 },
];
export default function Menu() {
const [items, setItems] = useState(initialItems);
const [selectedItem, setSelectedItem] = useState(
items[0]
);
return (
<>
<h2>What's your travel snack?</h2>
<ul>
{items.map(item => (
<li key={item.id}>
{item.title}
{' '}
<button onClick={() => {
setSelectedItem(item);
}}>Choose</button>
</li>
))}
</ul>
<p>You picked {selectedItem.title}.</p>
</>
);
}
현재 선택된 항목은 selectedItem state 변수에 객체로 저장됨 이것은 좋지 않음. selectedItem의 내용은 items 목록 내의 항목 중 하나와 동일한 객체로 즉, 항목 자체에 대한 정보가 두 곳에 중복됨.
selectedItem 객체(items 내부의 객체 복사본을 생성하는) 대신 selectedId를 state로 유지한 다음 items 배열에서 해당 ID를 가진 항목을 검색하여 selectedItem을 가져오기:
변경 전
items = [{ id: 0, title: 'pretzels'}, ...]
selectedItem = {id: 0, title: 'pretzels'}
items = [{ id: 0, title: 'pretzels'}, ...]
selectedId = 0
중복은 사라지고 필수 state만 유지됨
import { useState } from 'react';
const initialItems = [
{ title: 'pretzels', id: 0 },
{ title: 'crispy seaweed', id: 1 },
{ title: 'granola bar', id: 2 },
];
export default function Menu() {
const [items, setItems] = useState(initialItems);
const [selectedId, setSelectedId] = useState(0);
const selectedItem = items.find(item =>
item.id === selectedId
);
function handleItemChange(id, e) {
setItems(items.map(item => {
if (item.id === id) {
return {
...item,
title: e.target.value,
};
} else {
return item;
}
}));
}
return (
<>
<h2>What's your travel snack?</h2>
<ul>
{items.map((item, index) => (
<li key={item.id}>
<input
value={item.title}
onChange={e => {
handleItemChange(item.id, e)
}}
/>
{' '}
<button onClick={() => {
setSelectedId(item.id);
}}>Choose</button>
</li>
))}
</ul>
<p>You picked {selectedItem.title}.</p>
</>
);
}
중첩된 state를 업데이트하려면 변경된 부분부터 위쪽까지 객체의 복사본을 만들어야 함.
state가 너무 깊게 중첩되어 업데이트하기 어려운 경우 “flat(정규화)”하게 만드는 것을 고려하기
// before
export const initialTravelPlan = {
id: 0,
title: '(Root)',
childPlaces: [{
id: 1,
title: 'Earth',
childPlaces: [{
id: 2,
title: 'Africa',
childPlaces: [{
id: 3,
title: 'Botswana',
childPlaces: []
}, {
id: 4,
title: 'Egypt',
childPlaces: []
}, {
id: 5,
title: 'Kenya',
childPlaces: []
}, {
id: 6,
title: 'Madagascar',
childPlaces: []
}, {
id: 7,
title: 'Morocco',
childPlaces: []
}, {
id: 8,
title: 'Nigeria',
childPlaces: []
}, {
id: 9,
title: 'South Africa',
childPlaces: []
}]
}, {
id: 10,
title: 'Americas',
childPlaces: [{
id: 11,
title: 'Argentina',
childPlaces: []
}, ...]
}
]
}
// after
export const initialTravelPlan = {
0: {
id: 0,
title: '(Root)',
childIds: [1, 43, 47],
},
1: {
id: 1,
title: 'Earth',
childIds: [2, 10, 19, 27, 35]
},
2: {
id: 2,
title: 'Africa',
childIds: [3, 4, 5, 6 , 7, 8, 9]
},
3: {
id: 3,
title: 'Botswana',
childIds: []
},
4: {
id: 4,
title: 'Egypt',
childIds: []
},
5: {
id: 5,
title: 'Kenya',
childIds: []
},
6: {
id: 6,
title: 'Madagascar',
childIds: []
},
7: {
id: 7,
title: 'Morocco',
childIds: []
},
...
};
state를 원하는 만큼 중첩할 수 있지만 “flat”하게 만들면 많은 문제를 해결할 수 있고 state를 더 쉽게 업데이트할 수 있고 중첩된 객체의 다른 부분에 중복이 생기지 않도록 할 수 있음.