신나는 알고리즘 풀이 시간.
수포자는 수학을 포기한 사람의 준말입니다. 수포자 삼인방은 모의고사에 수학 문제를 전부 찍으려 합니다. 수포자는 1번 문제부터 마지막 문제까지 다음과 같이 찍습니다.
1번 수포자가 찍는 방식: 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ...
2번 수포자가 찍는 방식: 2, 1, 2, 3, 2, 4, 2, 5, 2, 1, 2, 3, 2, 4, 2, 5, ...
3번 수포자가 찍는 방식: 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, ...
1번 문제부터 마지막 문제까지의 정답이 순서대로 들은 배열 answers가 주어졌을 때, 가장 많은 문제를 맞힌 사람이 누구인지 배열에 담아 return 하도록 solution 함수를 작성해주세요.
나의 답.
function solution(answers) {
let answer = [];
const supo1 = [1, 2, 3, 4, 5];
const supo2 = [2, 1, 2, 3, 2, 4, 2, 5];
const supo3 = [3, 3, 1, 1, 2, 2, 4, 4, 5, 5];
const supo1score = [];
const supo2score = [];
const supo3score = [];
const supo1loop = Math.floor(answers.length / supo1.length) + 1;
const newSupo1 = [];
const newSupo2 = [];
const newSupo3 = [];
for (let i = 0; i < supo1loop; i++) {
newSupo1.push(...supo1);
newSupo2.push(...supo2);
newSupo3.push(...supo3);
}
for (i = 0; i < answers.length; i++) {
if (newSupo1[i] === answers[i]) {
supo1score.push(newSupo1[i]);
}
if (newSupo2[i] === answers[i]) {
supo2score.push(newSupo2[i]);
}
if (newSupo3[i] === answers[i]) {
supo3score.push(newSupo3[i]);
}
}
const [supo1Answer, supo2Answer, supo3Answer] = [
supo1score.length,
supo2score.length,
supo3score.length,
];
function findLargest(supo1Answer, supo2Answer, supo3Answer) {
const max = Math.max(supo1Answer, supo2Answer, supo3Answer);
if (supo1Answer === max) answer.push(1);
if (supo2Answer === max) answer.push(2);
if (supo3Answer === max) answer.push(3);
}
findLargest(supo1Answer, supo2Answer, supo3Answer);
return answer;
}
답이... 좀 길긴 하다.
풀이 과정을 생각하면 좀 단순하긴 한데.
먼저, 정답을 담는 배열 중에서 가장 작은 게 수포자 1의 배열이다.
가장 이상적인 방법은 각각 딱 문제 정답의 길이만큼 정해진 패턴대로 각자의 수포자들의 정답이 담긴 어레이를 생성하는 건데.
나는 그걸 할 여력이 안 돼서, 문제 정답을 가장 배열의 길이가 작은 수포자 1의 길이만큼 나눠서 1을 더했다. 이게 의미하는 건, 어레이를 반복할 횟수이다.
그 다음 새로운 수포자 1 배열을 만들어, 그 안에 횟수만큼 어레이를 새롭게 push해주었다. 이렇게 되면 정답을 체크하는데는 크게 문제가 없어진다.
문제의 정답 배열보다, 각 수포자듶의 정답 배열이 더 초과하는 현상은 발생하겠지만. 지금 문제에서는 별 문제가 되지 않는다.
아무튼 그 다음 for문을 통해 index가 완전히 일치하는 것만 선별해서 새로운 배열에 넣고, 그 배열으 length를 구하면 정답을 맞춘 개수를 구할 수 있다.
그 다음 그렇게 나온 length를 비교해 최대 최소를 구해서 알맞는 숫자를 push하면 끝이다.
개인과제 프로그레스
파비콘을 받았다. 이제부터 이거 쓸 거야!
const onSubmitForm = (e) => {
e.preventDefault();
if (Object.values(formData).includes("")) {
alert("존재하지 않는 국가입니다.");
return;
}
for (const data of medalLists) {
const { country } = data;
if (country === formData.country) {
alert(
"메달 리스트에 이미 존재하는 국가입니다. 업데이트 기능을 사용해주세요."
);
return;
}
}
setMedalList((medalLists) => {
return [...medalLists, formData];
});
const getItem = JSON.parse(localStorage.getItem("medalLists"));
getItem.push(formData);
localStorage.setItem("medalLists", JSON.stringify(getItem));
setFormData({
country: "",
goldMedal: "",
silverMedal: "",
copperMedal: "",
});
};
로컬 스토리지를 붙여서 데이터가 브라우저에 온존되도록 하였다.
로컬 스토리지의 키를 medalLists로 세팅해놓았는데, 세팅 과정은 이렇다.
const [medalLists, setMedalList] = useState(() => {
const savedMedalLists = localStorage.getItem("medalLists");
return savedMedalLists ? JSON.parse(savedMedalLists) : [];
});
useState의 기본값을 이렇게 설정해주었다.
savedMedalLists라는 변수에 로컬 스토리지에 있을 지 없을 지 모를 medalLists의 값을 갖고 오도록 한 다음, 이것의 참거짓을 따져서 있으면 getItem 해온 걸 기본값. 없으면 빈 배열을 기본 값으로 갖도록 하였다.
setMedalList((medalLists) => {
return [...medalLists, formData];
});
const getItem = JSON.parse(localStorage.getItem("medalLists"));
getItem.push(formData);
localStorage.setItem("medalLists", JSON.stringify(getItem));
로컬 스토리지를 쓰는데 있어서 단연 중요한 건, 바로 JSON이다.
로컬 스토리지의 value 값 안에 제대로 객체를 넣으려면, JSON을 이용한 포장이 필수적이다.
그래서 이런 식으로 변수를 통해 JSON을 이용해서 parse 해주고, 그 안에 formData 객체를 삽입한 다음 이를 다시 stringfy해서 최신화해주는 과정이 필요하다.
const updateBtn = (e) => {
if (Object.values(formData).includes("")) {
alert("업데이트할 데이터를 입력해주세요.");
return;
}
const revisedList = medalLists.map((list) => {
if (list.country === formData.country) {
return {
country: formData.country,
goldMedal: formData.goldMedal,
silverMedal: formData.silverMedal,
copperMedal: formData.copperMedal,
};
}
return list;
});
setMedalList(revisedList);
localStorage.setItem("medalLists", JSON.stringify(revisedList));
alert("업데이트 성공!");
setFormData({
country: "",
goldMedal: "",
silverMedal: "",
copperMedal: "",
});
};
업데이트도 마찬가지.
위에서 원래 사용했던 revisedList을 이용해 그대로 최신화를 조져주었다.
어떻게 업데이트를 할 지 막막했는데, 이런 방법이!
const DeleteBtn = (index, medalLists, setMedalList) => {
setMedalList(
medalLists.filter((l, i) => {
return i != index;
})
);
const newSetStorage = JSON.parse(localStorage.getItem("medalLists")).filter(
(l, i) => {
return i != index;
}
);
localStorage.setItem("medalLists", JSON.stringify(newSetStorage));
};
삭제 기능의 경우, 위에서 사용하였던 로직을 그대로 이용해 마찬가지로 로컬 스토리지 안의 데이터를 필터링해주는 식으로 구현하였다. setItem에 대한 감이 조금씩 왔다. 이건 '최신화'다!