ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • ⌚Tally String Times with Reduce⏱
    Web/JS30 2020. 11. 20. 18:50
    반응형

    오늘은 아주 간단한 예제이다.

    dataset, map, reduce 등을 이용해서 시간을 연산하는 방법에 관한 예제인데

    특별히 뭔가를 새로 배운다는 생각보다는, 다시 리마인드 한다는 느낌으로..

    위의 사진은 유튜브에 동영상을 올렸을 때, 유튜브측에서 제공해주는

    동영상의 길이를 나타내는 timestamp이다.

     

    흔히 이런 경우, 시간이 HTML 태그에 담겨져있는 경우가 많은데

    이 시간들을 DOM에서 뽑아내서, 문자열을 숫자로 변환하여 모두 더해주는 방법에 관한 내용이다.

    (dataset에 담겨있는 데이터는 모두 문자열이기 때문에 숫자로의 변환이 필요함.

    만약 span 같은 태그에 text로 담겨있다고 쳐도, 역시나 문자열이기 때문에)

     

    HTML 태그를 훑어보면 다음과 같다.

    <ul class="videos">
        <li data-time="5:43">
            Video 1
        </li>
        <li data-time="2:33">
            Video 2
        </li>
        <li data-time="3:45">
            Video 3
        </li>
    
    ...
    
        <li data-time="12:39">
            Video 56
        </li>
        <li data-time="1:56">
            Video 57
        </li>
        <li data-time="4:04">
            Video 58
        </li>
    </ul>

    우선, 이 li 태그들을 전부 잡아내어 변수에 담아줘야 하는데,

    그냥 'li'만 사용해서 얘네들을 잡아내는 건 썩 좋지 못한 방법이다.

     

    물론 이 상황에서는 가장 쉽게 li 태그들을 잡아내는 방법이겠지만

    모든 상황에서 'li'만으로 우리가 원하는 태그들을 잡아낼 수 있다는 보장이 없다.

    그래서 'data-time 속성을 가진 li'로 범위를 좁혀줘야 한다.

    const timeNodes = document.querySelectorAll('li[data-time]');

    그러면 현재 timeNodes에는 NodeList가 담겨져있는 상황인데, 얘를 배열로 만들어주는 방법은 두 가지가 있다.

    하나는 spread operator를 활용하는 방법이고, 하나는 Array.from을 활용하는 방법.

    const timeNodes = [...document.querySelectorAll('li[data-time]')];
    const timeNodes = Array.from(document.querySelectorAll('li[data-time]'));

    그리고는 map과 reduce를 활용하여 문자열을 변환하는 작업을 해준다.

    const seconds = timeNodes.map(node => node.dataset.time)
                             .map(timeCode => {
                                 const [mins, secs] = timeCode.split(':').map(parseFloat);
                                 return (mins * 60) + secs;
                             }).reduce((total, vidSeconds) => total + vidSeconds);

    처음 map에서는 nodeList의 각 node들에 담겨있는 data-time에 접근하여 문자열을 뽑아내고

    두 번째 map에서는 그 문자열을 ':'를 기준으로 분과 초로 분리해준다.

    이 때 ES6 Destructuring을 사용한 것에 주목할 것.

    그리고 한 가지 더 살펴볼 것은 map(parseFloat)이다.

    const [mins, secs] = timeCode.split(':').map(parseFloat);
    
    const [mins, secs] = timeCode.split(':').map(function(str) => {
                             return parseFloat(str);
                         });

    원래는 각 문자열에 parseFloat을 통해 숫자로 변환한다는 의미에서 아래와 같이 적어줘야 하지만

    간단하게 줄여서 위에 문장처럼 적는 것이 가능하다.

    parseFloat을 사용하지 않으면, 이상하게 어마어마한 숫자가 나온다.
    parsefloat을 통해 정상적으로 변한 숫자.

    그리고는 '분 * 60'을 해서 초 단위로 전부 통일시켜 준 후 이를 전부 더하여 

    동영상 길이를 모두 더한 것이 총 몇 초인지를 seconds 변수에 담았다.

     

    이제, 딱히 해줄 일은 없고

    시, 분, 초로 구분하여 콘솔에 출력해보고 예제가 종료되었다.

    let secondsLeft = seconds;
    
    const hours = Math.floor(secondsLeft / 3600);
    secondsLeft = secondsLeft % 3600;
    
    const mins = Math.floor(secondsLeft / 60);
    secondsLeft = secondsLeft % 60;
    
    console.log(hours, mins, secondsLeft);
    

    참고로, 시, 분을 구하고 나서 초는 따로 구해줄 필요 없이 그냥 그대로 secondsLeft를 사용해주면 된다.

    원래 초 단위였기 때문에, 시, 분을 구하고 남은 secondsLeft가 그대로 초에 사용되면 된다.

     

     

    그리고, 위에서 map을 사용한 것들은 전부 단계별로 과정을 보여주기 위해 사용한 것이고

    map을 사용하지 않고 하나의 reduce에다가 합쳐서 간단하게 만들어줄 수도 있다.

    const seconds = timeNodes.reduce((total, node) => {
        const [mins, secs] = node.dataset.time.split(':').map(parseFloat);
        return total + (mins * 60) + secs;
    }, 0);

    더 가독성 좋게 만들어줄 수도 있겠지만.

    이렇게 할 수 있다는 것.

     

    반응형

    'Web > JS30' 카테고리의 다른 글

    Following Along Links  (0) 2020.11.29
    🎤Native Speech Recognition📢  (0) 2020.11.23
    📊 Sort Without Articles 🎢  (0) 2020.11.19
    🤩 CSS Text Shadow Mouse Move Effect 😎  (0) 2020.11.18
    💿 LocalStorage & Event Delegation 📤  (0) 2020.11.17

    댓글

Designed by Tistory.