상권's

TIL 23 (2021.10.29) 본문

~2022 작성 글/TIL

TIL 23 (2021.10.29)

라마치 2021. 10. 29. 18:54
2021.10.29 오늘의 코플릿
문자열을 입력받아 문자열 내의 모든 괄호의 짝이 맞는지 여부를 리턴해야 합니다.
다음 단계에 맞춰 함수를 작성해 보세요
괄호의 종류를 단 한가지로 한정합니다.
괄호의 종류를 늘려 모든 종류의 괄호에도 작동하도록 합니다.
괄호를 제외한 문자열이 포함된 경우에도 작동하도록 합니다.
// str.split('') 해서 배열로 만들어준다.
// 앞에서 하나씩 빼면서 (, ) 가 맞다면 각각 다른 배열에 넣어준다.
// 두 배열의 길이가 맞다면 true를 리턴한다. => )( 이렇게 입력되는 경우에도 true가 뜬다... 
// 절반으로 나눠서 진행하는 건 어렵다... => stack 처럼 진행을 한다.

첫 수도코드 => 처음에는 괄호들이 (, ) 이렇게 들어오든, ), ( 이렇게 들어오든 짝은 맞으니깐 통과가 될 줄 알고, 수도코드처럼 코드를 구현해봤습니다. 근데, ), ( 의 경우에는 테스트 통과가 안되었습니다. 결국 구글링을 통해서 코드를 구현하게 되었습니다.

const balancedBrackets = function (str) {

  let brackets = { "(": ")", "{":"}", "[":"]" }

  let arr = str.split('')
  let result = arr.reduce(function(acc, cur) {
    if(cur === brackets[acc[acc.length - 1]]) {
      acc.pop()
    }
    else {
      acc.push(cur)
    }
    return acc
  }, [])
  return result.length === 0
}

brackets 객체에다가 괄호 별로 키와 벨류를 지정해줍니다. => 인자로 받는 문자열을 split을 통해서 배열로 만들어 줍니다. => 제일 첫번째 값은 acc에 push를 해줍니다. => 그 다음에 나오는 부분이 금방 들어갔던 값의 벨류에 해당하면 금방 들어갔던 값을 acc에서 pop해줍니다( 스택으로 LIFO 적용 ) => 아니라면 acc 추가합니다.(반복) => 모든 것이 짝이 맞다면 result의 length는 0이 됩니다. 짝인 안 맞으면 length는 0이 아닙니다.  


레프런스 코드도 확인을 했는데, 해당 방법이 더 간단하고 직관성이 있는 거 같습니다. 이러한 문제가 또 나온다면, 스택과 객체를 이용해서 풀 수 있도록 노력하겠습니다.

 


목, 금요일에 학습했던 CSS와 더불어서 React에서 모달, 토글, 탭, 태그 기능 구현했습니다. state, props 는 익숙해졌는데, styled-component 구현이 생각대로 되지 않아 css 비중이 작았던 탭과 태그에 대해서 먼저 올리고, 모달과 토글의 css에 대해서 학습한 후 이해가 되면 그때 올리도록 하겠습니다.

 

처음 storybook을 이용해봤는데, 사용법이 익숙하지 않지만, 해당 컴포넌트만 보여주기 때문에 작업하기 편리했습니다. 나머지 기능 css에 대해서 학습하면서 사용 방법을 익혀야겠습니다.

 

태그 기능.

export const TagsInput = styled.div`
  margin: 8rem auto;
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  min-height: 48px;
  width: 480px;
  padding: 0 8px;
  border: 1px solid rgb(214, 216, 218);
  border-radius: 6px;

  > ul {
    display: flex;
    flex-wrap: wrap;
    padding: 0;
    margin: 8px 0 0 0;

    > .tag {
      width: auto;
      height: 32px;
      display: flex;
      align-items: center;
      justify-content: center;
      color: #fff;
      padding: 0 8px;
      font-size: 14px;
      list-style: none;
      border-radius: 6px;
      margin: 0 8px 8px 0;
      background: #4000c7;
        > .tag-close-icon {
        display: block;
        width: 16px;
        height: 16px;
        line-height: 16px;
        text-align: center;
        font-size: 14px;
        margin-left: 8px;
        color: #4000c7;
        border-radius: 50%;
        background: #fff;
        cursor: pointer;
      }
    }
  }

  > input {    
    flex: 1;
    border: none;
    height: 46px;
    font-size: 14px;
    padding: 4px 0 0 0;
    :focus {
    outline: transparent;
  }
  }

  &:focus-within {
    border: 1px solid #4000c7;
  }

`;

export const Tag = () => {
  const initialTags = ['CodeStates', 'kimcoding'];

  const [tags, setTags] = useState(initialTags);

  const removeTags = (indexToRemove) => {
    let targetValue = tags.indexOf(indexToRemove.tag)
    // onClick이 작동이 된 태그의 인덱스를 찾는다.
    let removedArr = [...tags]
    removedArr.splice(targetValue, 1)
    //splice를 사용해서 해당 값을 tags에서 없앤다.
    setTags(removedArr)
  };
  
  const addTags = (event) => {
    if (event.code === 'Enter') {
      if (event.target.value === '') {
        return ''
      } // input에서 입력되는 값이 문자, 숫자는 태그를 작성하는 것이고,
      // enter가 눌러진다면, 태그를 추가한다.
      // 입력된 값이 없는데 enter가 눌러진다면 아무 일도 일어나지 않는다.
      else {
        if(tags.includes(event.target.value) === false) {
          const newTags = [...tags]
          newTags.push(event.target.value)
          setTags(newTags)
          event.target.value = ''
        }
        // 입력된 값이랑 기존에 있던 값이 같다면 추가되지 않으며,
        // 동일한 값이 없다면 태그에 추가되고, input은 빈칸이 된다.
        else {
          return ''
        }
      }
    }
  }
  

  return (
    <>
      <TagsInput>
        <ul id='tags'>
          {tags.map((tag, index) => (
            <li key={index} className='tag'>
              <span className='tag-title'>{tag}</span>
              <span className='tag-close-icon' onClick={({tag}) => removeTags({tag})}> X
              </span>
            </li>
          ))}
        </ul>
        <input
          className='tag-input'
          type='text'
          onKeyUp={(value)=> addTags(value)}
          placeholder='Press enter to add tags'
        />
      </TagsInput>
    </>
  );
};

탭 기능.

const TabMenu = styled.ul`
  background-color: #dcdcdc;
  color: rgba(73, 73, 73, 0.5);
  font-weight: bold;
  display: flex;
  flex-direction: row;
  justify-items: center;
  align-items: center;
  list-style: none;
  margin-bottom: 7rem;

  .submenu {
  // 기존적인 태그들에 적용될 css
    padding-left: 10px;
    padding-right: 50px;
    border-color: black;
  }

  .focused {
  // 클릭이 되는 태그에 적용될 css
    background-color: red;
  }

  & div.desc {
    text-align: center;
  }
`;

const Desc = styled.div`
  text-align: center;
`;

export const Tab = () => {

    const [currentTab, setCurrentTab] = useState(0)
    // 클릭이 되는 tag에 맞춰서 하단에 위치한 content가 변경되기 위해 state로 설정 

  const menuArr = [
    { name: 'Tab1', content: 'Tab menu ONE' },
    { name: 'Tab2', content: 'Tab menu TWO' },
    { name: 'Tab3', content: 'Tab menu THREE' },
  ];

  const selectMenuHandler = (index) => {
    setCurrentTab(index)
    // map을 통해서 index 나오고, 클릭되는 tag의 index를 파라미터로 받아서
    // currentTab를 바꾼다.
  };

  return (
    <>
      <div>
        <TabMenu>
          {menuArr.map((el, i) => {
            return (
            <li className={`submenu${currentTab === i ? " focused" : ""}`} key={i} onClick={() => selectMenuHandler(i)}>{menuArr[i].name}</li>
            )                // currentTab과 index가 같다면, focused class가 적용이되고, 나머지는 sunmenu만 적용된다.
          })}
        </TabMenu>
        <Desc>
          <p>{menuArr[currentTab].content}</p>
        </Desc>
      </div>
    </>
  );
};
Comments