오늘은 어떤 정보를 게시하기보다는, 풀기위해 시도했던 과정들을 한번 정리해보도록 하겠다.
문제는 다음과 같다.
Q) 문자열 중 숫자의 값의 합을, 숫자와 공백을 제외한 문자의 타입의 값의 개수로 나누어서 그 값을 정수로 반올림하라.
나는 이 문제를 보고, 먼저 저 문자열을 '유사배열'로 접근하는 방식을 생각했었다.
- document의 모든 tag들(node)
// NodeList [div, div, div, div, div, ...]
- noscript등을 포함한 HTMLCollection들
- 문자열
- length속성을 지닌 객체
즉, 유사배열은 []으로 감싸져있지만 배열이 아닌 것들을 의미한다.
때문에 형태만 배열로 보일 뿐, array메소드들을 사용할 수 없다. 말 그대로 가짜배열이니까!
때문에 고차함수로 한글자씩 뜯어보면서 그 값의 진위여부를 판단하여 숫자값에 계속 더하고, 숫자나 공백 즉 숫자타입이 아닌 값들은 배열에 넣어서 그 길이를 판단할 수 있게!
... 내가 처음에 생각한 식은 이것이었다.
function numberSearch(str) {
//문자열을 입력받아, 그 중 요소가 '숫자'인 것을 모두 찾는다.
//그 요소들만 전부 더한후,그 값을 문자열 중 '숫자,공백이 아닌 요소들의 갯수'로 나눈 값을,
//정수로 반올림하여 리턴해야 한다.
//*빈 문자열을 입력받은 경우 0을 리턴해야한다.
let onlyNum = 0;
let ignoreNum = 0;
if(str.length===0){
return 0;
}
let newArr1 = [].filter.call(str, (function (i) { //얘가 숫자아닌거
return (str[i]===null || str[i]===undefined);
}));
let newArr2 = [].filter.call(str, (function (i) { //얘가 숫자.
if(typeof Number(str[i]) === 'number'){
return str[i];
}
}));
for(let i=0;i<newArr2.length;i++){ //숫자인것 다 계산
onlyNum = onlyNum + Number(newArr2[i]);
}
for(let i=0;i<newArr1.length;i++){
ignoreNum = ignoreNum + 1;
}
console.log(onlyNum);
console.log(ignoreNum);
return Math.floor(onlyNum/ignoreNum);
}
빈 배열 '[]'을 기준으로, call을 사용하여 유사배열에도 고차함수를 사용할 수 있게 하여, array 프로토타입 filter 를 가져와서 숫자값, 숫자가 아닌 값들을 골라낼 수 있게 하는게 처음 생각이었다.
코드리뷰
변수 newArr2에 들어가는 값들은 한 눈에도 뭐가 들어가는지 잘 보인다. 그러나, 숫자가 아닌 값들을 거르기 위해서 조건을 작성하는게 쉽지않았다. 😥😥
1차시도
let newArr1 = [].filter.call(str, (function (i) { //얘가 숫자아닌거
return (!(typeof Number(str[i]) === 'number'));
//전혀 걸러지지 않고, 아예 이 if문을 건너뛰어버린다 ㅠㅠ
}));
2차시도
let newArr1 = [].filter.call(str, (function (i) { //얘가 숫자아닌거
return (str[i]===null || typeof str[i]=== NaN);
//코플릿에서 풀었잖아! NaN은 자기자신과도 비교할 수 없기때문에 정확한 계산이 필요해!!
}));
3차시도
let newArr1 = [].filter.call(str, (function (i) { //얘가 숫자아닌거
return (str[i]===null ||isNaN(Number(str[i])));
//isNaN을 그래서쓴건데 자꾸 undefined가 나오네..?
//게다가, str[i]===null < 이 조건만 넣었을때도 안되서
//두 조건을 같이 거르든 하나만 넣든 어차피 안된다.
//json.parse()도 먹히지않았다.
//(여기서 뭔가 문제가 생겼다는걸 인지하지 못함.)
}));
3차시도
let newArr1 = [].filter.call(str, (function (i) { //얘가 숫자아닌거
return (str[i]===null ||str[i]===undefined);
//해서 그래, 니가 undefined를 뱉어낸다면, 그 타입이라는 거겠지. 니가 원하는대로 해줄께-
//해서 undefined로 쐐기를 박음. > 'hello6 '문자열 거르기 성공.
}));
그러나 이상하게도 몇몇 문자열들은 걸러지지 않는것이었다. 똑같이 숫자 문자 공백을 섞은 문자열인데 몇개는 안 걸러지니 진이 빠졌다. 해서 레퍼런스를 확인했는데...
정확히는 거르는거에 집중하기보단, 이 엔지니어분도 뭔가 그런 부분을 많이 시행해보셨는지 비교의 접근으로 작성해주셨다.
let digits = '0123456789'; //미리 비교할 문자열 타입 수를 하나 선언
if(str===''){
return 0;
}
let sum=0;
let pureStr = '';
for(let i=0;i<str.length;i++){
if(digits.includes(str[i])){ //str의 i번째 문자열형 숫자 중 숫자데이터가 하나라도 있으면
sum = sum+Number(str[i]); //넘버형으로 바꿔서 sum에 더하기.
}else if(str[i]!==' '){ //string형 숫자데이터가 '아닌'것중에서, '공백'도 아닌것 거르기.
pureStr += str[i]
}
}
return Math.round(sum/pureStr.length); //MAth.round()로 소수점 이하를 반올림한다.
filter가 걸러주지 못했던 이유가 뭔지 안타깝게도 아직 찾지못했다. 분명하게 '!'연산자를 썼는지 거르지 못한 이유는 ? 뭘까..?