공통된 문제 하나씩 풀어와서 서로 설명해주는 오프라인 스터디

문제 풀이 의식의 흐름

먼저 left와 right의 약수의 개수를 구해야하고, 개수가 짝수이면 더하고 홀수이면 빼야한다

 

// 석우님의 풀이
function solution(left, right) {
    
    // 주어진 숫자의 약수를 구해 반환하는 함수
    function 약수(num) {
        const result = [];
        for (let i = 1; i <= num; i++) {
            if(num % i === 0) {
                result.push(i);
            }
        }
        return result;
    }
    
    // left부터 right까지의 숫자 생성
    const 대상 = new Array(right - left + 1).fill().map((number, index) => left + index);
    
    console.log(대상)
    return 대상.reduce((acc, number) => {
        if (약수(number).length % 2 === 0) {
            acc += number;
        } else {
            acc -= number;
        }
        return acc;
    }, 0);
}
// 성진님의 풀이
function solution(left, right) {
    var answer = 0;

    function divisorNum (n){
        let num = 0; 
        for(let i=1; i<= Math.sqrt(n); i++){
            if(n % i === 0 && i === Math.sqrt(n)){
                num += 1
            }
            else if(n % i ===0){
                num += 2
            }
        }
        return num;
    }
    ///// 약수 구해주는 함수 끝          


    for(let i= left; i<= right; i++){
        if(divisorNum(i) % 2 === 0) answer += i
        else if(divisorNum(i) % 2 !== 0) answer -= i
    }
    

    return answer;
}
// 도영님의 풀이
function solution(left, right) {
    var answer = 0;
    const num = right - left + 1 //갯수
    let cnt = 0; //약수의 갯수
    
    for(let i = 0; i < num ; i++){
        for(let j = 1; j <= left; j++){
            if(left % j === 0){
                cnt++ 
            } //left에서 약수의 갯수를 계산
        }
        //약수에 갯수에 따라서 덧셈, 뺄셈을 진행
        cnt % 2 === 0 ? answer += left : answer -= left
        
        //다음 값을 탐색하기 위해 left에 1을 더하고, cnt를 0으로 초기화
        left++
        cnt = 0
    }
    return answer;
}
// 윤정님의 풀이
function solution(left,right){
            let sum = 0;
            for(i=left;i<=right;i++){
            let count=0;
            for(j=1;j<=i;j++){
                if(i%j===0){
                    count++
                }
            }
            if(count%2===0){
                sum += i;
            }else{
                sum-=i;
            }
        }
            return sum
        }
// 민승님의 풀이
function solution(left,right){
var answer = 0;
    for(let i=left;i<=right;i++){
        let count = 0;
        for(let j=1;j<=i;j++){
            if (i%j ===0){
            count++
            } 
        } count%2===0?answer+=i:answer-=i;     

    }

    return answer

글자수 제한으로 짤린 썸네일;

답장 메세지를 입력하는 인풋창에 있는 플레이스 홀더 텍스트 색상을 변경하고 싶었다

원래 이색이 아녔음

  • 컴포넌트
<ReplyInputText
    value={input}
    onChange={handleCheckValid}
    type="text"
    placeholder="메세지 입력하기..."
/>
  • 스타일 컴포넌트
const ReplyInputText = styled.input`
    &::placeholder {
        color: #c4c4c4;
    }
    padding: 18px;
    flex-grow: 1;
`;

 

&:: 를 앞에 붙여주면 되는것이었다 초간단!

협업 프로젝트를 하면서 각자 기능에 따른 새로운 브랜치를 파서 작업한다

이때 주의해야할 점을 경험으로 깨달아 적어둔다

 

git pull 에서 오류가 나지 않게 하려면

 

  1. develop branch 에서 먼저 git pull 로 데이터를 받아온다
  2. 내가 작업할 새로운 브랜치를 판다
  3. 새 브랜치에서 git merge develop 해서 데이터를 병합한다
  4. 작업한다

참고로 여기서 develop은 필자가 작업하기로 한 메인 브랜치(default branch)다

만약 default branch의 이름이 main 이라면 똑같이 이름만 바꿔 진행하면 된다!

 

프로젝트를 해보니 생각보다 깃에서 꼬이고 삽질하는 리소스가 많이 소모된다

사용법을 잘 익혀야겠다

 

현상황: 모종의 이유로 프로젝트 폴더 삭제했다가 다시 땡겨온 상황
npm start 에서 오류메세지가 뜸

 

sh: react-scripts: command not found

 

빠른 해결을 위한 해결방법 요약

 

  1. npm start 하는 위치 확인 엉뚱한 디렉토리에서 하고 있는게 아닌지
    (필자는 이부분이 맞았다)
  2. 아니라면 npm install
  3. 다시 npm start
  4. 안된다면 node_modules 폴더 지웠다가 npm install 해보기
  5. npm start

 

처음에 npm install 했을 때

npm audit fix --force 을 하라는 메세지도 같이 나오지만 찾아보니

오히려 이렇게 했을 때 프로젝트가 망가지는 경우도 있다고 하여 일단 후퇴.

 

그리고 혹시나 하여 src가 아닌 전체 프로젝트로 빠져나와 npm start를 해보았는데, 된다!

 

구글링한 해결방법 중 node노드 모듈 폴더를 삭제하고 다시 설치하라는 방법도 있었는데,

노드 모듈 폴더가 src 폴더 바깥에 위치해 있어서 그랬던거 아닐까 싶다 (단지 나의 추측이긴하다)

공통된 문제 하나씩 풀어와서 서로 설명해주는 오프라인 스터디

문제 풀이 의식의 흐름

나머지가 1이 되게 하는 가장 작은 자연수를 찾는 문제

 

  1. n 값에서 1을 뺀다 (나머지가 1이기 때문에 역순으로 풀어봄)
  2. 그 값에서 최소 공배수를 구해 리턴한다

이렇게 생각했는데 그럴 필요도 없는 문제였다

 

const solution(n) {
  for (let i = 2; i < n; i++) {
    if (n % i === 1) return i;
  }
};

 

%를 사용하면 된다

제한사항으로 n 이 3부터 시작, 최소값은 2부터 가능하므로

for 문을 i를 2부터, i 는 n 보다 작고, 순회한다

만약 n 을 i로 나눈 나머지 값이 1과 같다면 그때 i 값을 출력한다

 

공통된 문제 하나씩 풀어와서 서로 설명해주는 오프라인 스터디

문제 풀이 의식의 흐름

배열에서 공통된 요소가 가장 많은 요소를 나타내야한다

각 요소의 갯수가 똑같을 시에는 -1을 리턴해야하는 약간 까다로운 문제

 

  1. 배열에서 각 요소의 갯수를 세주고
  2. 갯수들 중 최대값을 뽑아야한다
  3. 최대값이 같은 것이 2이상 나오면 -1을 리턴한다
  4. 그렇지 않다면, 최대값에 해당하는 요소를 나타낸다

생각은 했지만 구현은 어려워 풀지 못하고, 동료들의 풀이를 들어봤다

// 석우님 풀이
function solution(array) {
    let answer = 0;
    let 값 = new Set(array)
    let 종합 = {};
    for (const number of 값) {
        종합[number] = array.filter(element => element === number).length
    }
    let 개수 = Object.values(종합)
    answer = +Object.keys(종합).find(key => 종합[key] === Math.max(...개수))
    개수.indexOf(Math.max(...개수)) !== 개수.lastIndexOf(Math.max(...개수)) ? answer = -1 : 0

    return answer;
}
    // for (const number of 값) {
    //     let 개수 = array.filter(element => element === number).length
    //     개수 > answer ? answer = number : 0
    // }
// 도영님의 풀이
function solution(array) {
    let temp = {}
    let cnt = 0;
    
    for(i in array){
        temp[array[i]] = array.filter(v => v === array[i]).length
    }
    let maxCnt = Math.max(...Object.values(temp))
    for(i of Object.values(temp)){
        if(maxCnt === i){
            cnt++}
    }
    if(cnt > 1){
        return -1
    }else{
        return +Object.keys(temp)[Object.values(temp).indexOf(maxCnt)]
    }
}
// 성진님의 풀이 - 1
function solution(array) {
    var answer = [];

    let arr = new Set(array);
        arr = [...arr]
   // console.log(arr)
    for(let value of arr){     
        let num = 0;
        for(let i=0; i<array.length; i++){
            if(value === array[i]) num += 1
        }
        answer.push(num)
    }
    //  console.log(answer)
    
     let result = Math.max(...answer);
    // 만약 answer 배열에서 result값이 두개 이상이면 -1을 리턴
    // 아니라면 result값을 arr에서 찾아서 그 값을 리턴
   if(answer.filter(e => e === result).length >= 2) return -1
    else return arr[answer.indexOf(result)]
}

// 2
function solution(array) {

    let arr = new Map();
    
    for(let i of array){
        arr.set( i , (arr.get(i) || 0) +1)
    }
    
    let result = [...arr].sort((a,b) => b[0] - a[0]); // 원소 먼저 정렬
        result.sort((a,b) => b[1] - a[1]); // 최빈값 정렬
    
    if( result.length === 1) return result[0][0]
    else if( result[0][1] === result[1][1]) return -1
    else return result[0][0]
}

// 3 
function solution(array) {
    
    let copy = [...array]; // 삭제될 배열을 만들어줌
   
    let result = {};
    
    for(let i of array){
        result[i] = 0;
    }
    // console.log(result)
    // 위 코드는 각 요소의 초깃값을 설정

    for(let i of array){
        
        if(copy.includes(i)){
            copy.splice(copy.indexOf(i),1);
            result[i]++
        }
    }

    result = Object.entries(result);
    result.sort((a,b) => b[1] - a[1])
    return (result.length === 1 || result[0][1] > result[1][1]) ? parseInt(result[0][0]) : -1;
}

 

참고

  • 모던자바스크립트
    map set (새로운 배열을 만든다)
  • ... 스프레드 문법
    Object.values() 값만 뽑아내는 문법
  • length를 활용하자

 

 
 
리액트 스타일 컴포넌트로 프로젝트 중 가상요소를 넣었어야 했다

첫번째로 시도 했을때도 구글링으로 헤메다 물어물어 겨우 했었는데,

두번째 시도때에 똑같은 방법으로 가상요소를 적용하려는데 적용이 되지 않았다

 

바로 그 원인은 요소 자신에게 주느냐, 자식요소에 주느냐에 따라서였는데,

가상요소의 대상이 어딘지에 따라 사용법이 조금씩 달랐다

 

가상요소를 적용하고자 하는 부분이 어느 위치인지 이점을 분명히 알아야 할 필요가 있다

 

1. 부모 스타일 컴포넌트 안에서 특정 자식 클래스 요소에 가상 요소 주는 법

 

첫번째 사례로는 이메일 버튼으로 묶여있는 컴포넌트 안에서

구분선을 추가하기 위해 자식 요소인 클래스들 중 하나에 가상요소를 주고 싶었다

 

<LoginForm>
    <SocialLogin>
        <SocialBtn className='kt'>카카오톡 계정으로 로그인</SocialBtn>
        <SocialBtn className="gg">구글 계정으로 로그인</SocialBtn>
        <SocialBtn className="fb">페이스북 계정으로 로그인</SocialBtn>
    </SocialLogin>
    <EmailDiv className="btnEmailLogin-Join">
        <EmailButton className="btnEmailLogin">이메일로 로그인</EmailButton>
        <EmailButton className="btnJoinLogin">회원가입</EmailButton>
    </EmailDiv>
</LoginForm>

자식 클래스에 가상요소 주는 법

    const EmailDiv = styled.div`
        display: flex;
        padding-top: 20px;
        justify-content: center;
        gap: 32px;
        .btnEmailLogin::after {
            content: '';
            background-color: #C4C4C4;
            width: 0.8px;
            height: 11px;
            position: absolute;
            margin: 5px 22px;
        }
    `;

 

이렇게 부모 스타일 컴포넌트에서 가상요소를 부여할 자식 클래스명으로 가상요소를 부여하였다

 

.자식클래스명::after, before {

    가상요소 속성 입력

}

 

결과 : 구분선 속성을 가상요소로 나타내었다

 

 

2.  스타일 컴포넌트 안에서 클래스 자기자신에 가상 요소 주는 법

 

두번째로 헤맷던 부분은 가상요소를 그안에서 주려고 했을 때였다

앞의 방법과 같이 입력했지만 동작하지 않았고,

자식요소가 아닌 클래스 자기 자신에게 가상요소를 줄때는 다른 방법으로 사용하면 된다는 것을 알게 되었다

                <ChatBoard>
                    <ChatList className="newChat">
                        <ChatProfile />
                        <ChatWrap>
                            <ChatUserName>리듬이</ChatUserName>
                            <ChatPreview>책 주세요</ChatPreview>
                        </ChatWrap>
                        <ChatDate>2022.12.25</ChatDate>
                    </ChatList>
                    <ChatList>
                        <ChatProfile />
                        <ChatWrap>
                            <ChatUserName>뽐내기 좋아하는 사자</ChatUserName>
                            <ChatPreview>모던 자바스크립트 구매원합니다</ChatPreview>
                        </ChatWrap>
                        <ChatDate>2022.12.24</ChatDate>
                    </ChatList>
                        <ChatDate>2022.12.09</ChatDate>
                    </ChatList>
                </ChatBoard>

 

여기서 newChat 이라는 클래스 자체에 가상요소를 주고 싶었다

 

const ChatList = styled.li`
    font-size: 14px;
    line-height: 18px;
    display: flex;
    flex-direction: row;
    &.newChat::after {
        content: '';
        position: absolute;
        width: 12px;
        height: 12px;
        border-radius: 6px;
        background-color: #c55854;
        top: 75px;
    }
`;

 

이렇게 클래스 명 앞에 . 이 아닌 &.으로 표기해주면 잘 나타난다

 

&.자식클래스명::after, before {

    가상요소 속성 입력

}

 

결과: 새로온 메세지 알림을 임시로 가상요소로 표현해 보았다

 

 

이렇게 가상 요소를 주고자하는 위치에 따른 사용법을 프로젝트를 통해 알게 되었다

새로운 사실을 깨우치는 느낌은 너무 즐겁다!

알고리즘 문제를 풀면서 알게된 오름차순 정렬과 내림차순 정렬

공식처럼 알고있지만 어떤 원리로 정렬되는지 궁금해 찾아보았다

 

MDN 공식문서를 살펴보자

 

compareFunction이 제공되지 않으면 요소를 문자열로 변환하고 유니 코드 코드 포인트 순서로 문자열을 비교하여 정렬됩니다.

예를 들어 "바나나"는 "체리"앞에옵니다.
숫자 정렬에서는 9가 80보다 앞에 오지만 숫자는 문자열로 변환되기 때문에 "80"은 유니 코드 순서에서 "9"앞에옵니다.

compareFunction이 제공되면 배열 요소는 compare 함수의 반환 값에 따라 정렬됩니다.
a와 b가 비교되는 두 요소라면, compareFunction(a, b)이 0보다 작은 경우 a를 b보다 낮은 색인으로 정렬합니다.
즉, a가 먼저옵니다.compareFunction(a, b)이 0을 반환하면 a와 b를 서로에 대해 변경하지 않고 모든 다른 요소에 대해 정렬합니다.
참고 : ECMAscript 표준은 이러한 동작을 보장하지 않으므로 모든 브라우저(예 : Mozilla 버전은 적어도 2003 년 이후 버전 임)가 이를 존중하지는 않습니다.

compareFunction(a, b)이 0보다 큰 경우, b를 a보다 낮은 인덱스로 소트합니다.

compareFunction(a, b)은 요소 a와 b의 특정 쌍이 두 개의 인수로 주어질 때 항상 동일한 값을 반환해야합니다.
일치하지 않는 결과가 반환되면 정렬 순서는 정의되지 않습니다.

 

...쉽게 풀어쓰면

 

기본적으로 sort() 을 했을 땐 유니코드 포인트 순서대로 정렬한다

9와 80 중 80이 더 큰 숫자이지만 숫자가 아닌 문자로 보면 9보다 8이 더 작기 때문에 80을 일단 앞에 세운다

 

우리가 원하는 오름차순을 위해선 compareFunction(비교함수) 를 넣어주자

 

const arr = [5, 9, 22, 50, 109]
배열 먼저 선언해준다

arr.sort((a,b)=>a-b);
(5) [5, 9, 22, 50, 109]
오름차순

arr.sort((a,b)=>b-a);
(5) [109, 50, 22, 9, 5]
내림차순

a-b 라는 식의 값이

0보다 작을 경우, a 가 b 앞에 오도록 정렬한다

0보다 클 경우, b가 a보다 앞에 오도록 정렬한다

0일 경우, 정렬을 변경하지 않는다

 

이는 a 와 b 의 값을 바꿨을때도 동일한 논리로 연산되어 내림차순이 완성되는 것이다!!

 

 

알고리즘 문제를 풀다보면 Math.floor를 이용할 때가 많다

그런데 parseInt를 사용해도 상관없는 경우가 많았다

그렇다면, 이 둘의 차이는 무엇일까?

 

먼저, Math.floor() 란 간단히 말해 버림이다

 

출처 : MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor

 

 MDN 공식 문서의 정의로는 주어진 숫자와 같거나 작은 정수 중 가장 큰 수를 반환한다

 

parseInt 도 마찬가지로 정수를 반환한다

 

 

MDN 공식 문서의 정의로는 문자열 인자를 파싱하여 특정 진수의 정수를 반환한다

이렇듯, parseInt 의 동작방식은 조금 다르다

 

(개인적인 생각인데, 이렇게 문자열 인자로 받고 다시 숫자로 반환하는게

숫자만 계산할때는 불필요한 움직임인가 아닌가 싶다)

 

여기서 차이점을 알 수 있다

parseInt는 문자열 인자를 파싱하기 때문에

 

console.log(parseInt('109 백구'))
109

console.log(parseInt('백구 109'))
NaN

console.log(Math.floor('109 백구'))
NaN

console.log(Math.floor('백구 109'))
NaN

 

'109 백구'과 같이 문자열과 같이 있는 값에서

숫자가 시작하는 부분부터 끝나는 부분까지 저장하여 형변환이 된다

 

반면 '백구 109' 라는 문자열이 먼저오는 값은 숫자가 먼저 나오지 않아서인지 NaN값이 나온다

 

연산속도는 Math.floor가 좀 더 빠르다

 

하지만 둘의 차이는 음수에서도 나타난다

 

console.log(Math.floor('-1.5'))
-2

console.log(parseInt('-1.5'))
-1

console.log(Math.floor('-1.1'))
-2

console.log(parseInt('-1.1'))
-1

 

Math.floor는 앞서 말했듯 숫자의 버림과 같다

 

-1.5 이든, -1.1 이든간에 소수점 자리를 버리면 숫자는 더 큰 숫자가 되어버린다

(-1이 -1.5와 -1.1보다 큰 숫자니까 '버림'이 아닌 '더함'이 되버린다)

 

그래서 더 음수쪽에 가까운 정수인 -2라는 값이 나온다

 

한편, parseInt 는 숫자열을 문자열로 변환후 정수만 도출해내므로 소수점 앞의 숫자열인 -1 만 도출해낸다

 

결론

알고리즘 문제 풀 때 양수일땐 속도가 더 빠른 Math.floor를 사용하되,

문자열과 같이 있거나 음수일땐 parseInt를 사용한다

아니다.

 

Math.floor 와 같으면서 더 빠른 연산자가 있다 ~~

~연산자 를 두개 붙인 ~~ 연산자는 Math.floor 와 똑같은 기능을하면서도 더 빠른 속도로 값을 도출해낸다

 

round, floor, ceil

또, MDN 공식문서에서 재밌는 사실을 알게 되었다

 

round 반올림
floor 내림(버림)
ceil 올림

 

이렇게 자바스크립트 연산자로 반올림, 내림(버림), 올림 하는 법까지 알아보았다

새로운 정보를 알게되어 흥미로웠다

Mac 을 새로 급하게 산 뒤 초기 세팅 중 우여곡절 끝에 힘겹게 홈브루를 설치하고..

 

맥은 깃이 자동으로 깔려있다고?!

git --version

깃버전도 확인했다

git clone URI

깃 클론도 완료!

 

자이제 해볼까

?!

 

아 이것은 현재 폴더에 깃에 대한 정보를 담은 파일 .git 이 없었기 때문이었다

깃이 바로 우리 파일에 대한 로그를 저장하는건데 그게 없으니까!

 

해결법은 간단하다 깃을 설정해주면 된다

 

$git init

완료!

+ Recent posts