<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>l-suyeon-l.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sat, 07 Feb 2026 06:47:22 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>l-suyeon-l.log</title>
            <url>https://velog.velcdn.com/images/l-suyeon-l/profile/0ac729ae-f0eb-4dbc-a86f-4082b7711166/social_profile.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. l-suyeon-l.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/l-suyeon-l" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Arrays.sort() VS Collections.sort() / 
Comparable VS Comparator]]></title>
            <link>https://velog.io/@l-suyeon-l/Arrays.sort-VS-Collections.sort-Comparable-VS-Comparator</link>
            <guid>https://velog.io/@l-suyeon-l/Arrays.sort-VS-Collections.sort-Comparable-VS-Comparator</guid>
            <pubDate>Sat, 07 Feb 2026 06:47:22 GMT</pubDate>
            <description><![CDATA[<p>이 문서는 자바를 공부하면서 가장 헷갈렸던 부분, 정리되지 않았던 부분인 연속 자료형의 정렬에 대한 정리 문서이다.</p>
<br>

<h2 id="arrayssort-vs-collectionssort">Arrays.sort() vs Collections.sort()</h2>
<p>자바에서 정렬을 할 때에는 크게 두 가지 방법이 있다.</p>
<ul>
<li>Arrays.sort()</li>
<li>Collections.sort()</li>
</ul>
<p>둘 다 정렬할 때 쓰이지만 <strong>적용 대상</strong>과 <strong>내부 동작</strong>에서 차이가 있다.</p>
<br>

<h3 id="1-arrayssort">1. Arrays.sort()</h3>
<ul>
<li>대상 : 배열(array)</li>
<li>라이브러리 : java.util.Arrays</li>
</ul>
<pre><code class="language-java">public static void main(String[] args) {
    int[] arry = {5, 3, 1, 4, 2};

    Arrays.sort(arry);    // 기본 오름차순 정렬
    System.out.println(Arrays.toString(arry));    // [1, 2, 3, 4, 5]
}</code></pre>
<p>⇒ Arrays.sort()에서는 Comparator가 사용 불가능하다.</p>
<br>

<h3 id="2-collectionssort">2. Collections.sort()</h3>
<ul>
<li>대상 : 리스트(List)</li>
<li>라이브러리 : java.util.Collections</li>
</ul>
<pre><code class="language-java">public static void main(String[] args) {
    List&lt;Integer&gt; list = Arrays.asList(5, 3, 1, 4, 2);

    Collections.sort(list);
    System.out.println(list);    // [1, 2, 3, 4 ,5]

    Collections.sort(list, Comparator.reverseOrder());    // Comparator 내림차순 정렬
    System.out.println(Arrays.toString(list));    // [5, 4, 3, 2, 1]
}</code></pre>
<p><br><br></p>
<p><strong>정리</strong></p>
<table>
<thead>
<tr>
<th>적용 대상</th>
<th>배열(Array)</th>
<th>리스트(List)</th>
</tr>
</thead>
<tbody><tr>
<td>소속 클래스</td>
<td>java.util.Arrays</td>
<td>java.util.Collections</td>
</tr>
<tr>
<td>반환 값</td>
<td>없음 (원본 배열 수정)</td>
<td>없음 (원본 리스트 수정)</td>
</tr>
<tr>
<td>지원 타입</td>
<td>기본형 배열(int[], String[] 등), 객체 배열</td>
<td>객체 타입 리스트(List<T>)</td>
</tr>
<tr>
<td>정렬 기준</td>
<td>기본 오름차순, Comparator 가능</td>
<td>기본 오름차순, Comparator 가능</td>
</tr>
</tbody></table>
 <br>


<p><a href="https://hianna.tistory.com/923">참고문서) [Java 기초] Arrays.sort() vs Collections.sort() 차이 정리</a></p>
<p>  <br><br><br></p>
<h2 id="comparable-vs-comparator">Comparable vs Comparator</h2>
<p>자바에서 컬렉션을 정렬하는 방법에는 두 가지가 있다.</p>
<ul>
<li><p>Comparable 인터페이스에 compareTo 구현</p>
</li>
<li><p>Comparator 인터페이스에 compare 구현</p>
<br>

</li>
</ul>
<h3 id="1-comparable-인터페이스---compareto">1. Comparable 인터페이스 - compareTo()</h3>
<p>Comparable 인터페이스는 객체 자체에 기본적인 정렬 기준을 설정하는 인터페이스다. 해당 클래스가 Comparable&lt;클래스명&gt;을 implements하고, compareTo() 메서드를 Override하면 기본 정렬 기준을 정의할 수 있다.</p>
<pre><code class="language-java">public class Student implements Comparable&lt;Student&gt; {
    private int StudentNo;
    private String name;
    private String number;
    private int age;
    private String major;

    // 생성자 및 getter, setter

    @Override
    public int compareTo(Student o) {
        return this.getStudentNo() - o.getStudentNo();    // 학번 오름차순 정렬
    }
}</code></pre>
<p>  <br><br></p>
<p><strong>Comparable&lt;&gt;을 implements해야 하는 이유?</strong></p>
<p>⇒ Integer, Double과 같은 자바가 기존에 Comparable을 구현해놓은 Wrapper 클래스가 아닌 <strong>사용자가 직접 생성한 클래스 객체</strong>는 컴퓨터가 어떤 멤버 변수를 기준으로 정렬할 지 모르기 때문에 사용자가 직접 Comparable 인터페이스를 implements해서 compareTo() 메서드에 클래스 정렬 기준을 명시해야 한다.</p>
<p>⇒ Collections.sort()의 내부 구조를 보면 인자로 받는 리스트의 요소들이 반드시 Comparable&lt;&gt;을 구현하고 있어야 한다고 정의되어 있다.</p>
<p>  <br><br><br></p>
<h3 id="2-comparator-인터페이스---compare">2. Comparator 인터페이스 - compare()</h3>
<p>Comparator 인터페이스는 클래스에 정렬 기준을 고정시키지 않고 필요할 때마다 원하는 정렬 기준을 동적으로 적용할 수 있다. Comparator을 사용하면 다양한 방식으로 객체를 정렬할 수 있다.</p>
<pre><code class="language-java">public static void main(String[] args) {
    List&lt;Student&gt; list = new ArrayList&lt;&gt;();
    // 리스트 요소 추가(생략)

    Collections.sort(list, new Comparator&lt;Student&gt;() {
        @Override
        public int compare(Student o1, Student o2) {
              if(o1.getMajor().equals(o2.getMajor())    
                return o2.getAge() - o1.getAge();    // 나이 내림차순 정렬
              return o1.getMajor().compareTo(o2.getMajor());
        }
    }
}</code></pre>
  <br>


<p><strong>클래스에서 Comparable&lt;&gt;의 compareTo()를 오버라이딩 했는데 main에서 Comparator&lt;&gt;의 compare()을 다시 오버라이딩한 경우</strong></p>
<p>⇒ compareTo() 메서드는 클래스 내부에 그대로 유지되지만, Collections.sort()의 두 번째 인자에 Comparator을 넘기면, 자바는 compareTo()를 무시하고 인자로 넘겨받은 compare()의 규칙을 최우선으로 적용함</p>
<ul>
<li><p><strong>Comparable&lt;&gt;의 compareTo()</strong> : 객체의 기본 정렬 기준 (하나만 설정 가능)</p>
</li>
<li><p><strong>Comparator&lt;&gt;의 compare()</strong> : 객체의 특별 정렬 기준</p>
<p><br><br></p>
</li>
</ul>
<p><strong>return 방식</strong></p>
<ul>
<li>숫자형(int) 비교 방식</li>
</ul>
<pre><code class="language-java">@Override
public int compare(Student o1, Student o2) {
    return o1.getStudentNo() - getStudentNo();
}</code></pre>
<pre><code class="language-java">@Override
public int compare(Student o1, Student o2) {
    return Integer.compare(o1.getStudentNo(), o2.getStudentNo());
}
</code></pre>
<p>⇒ o1.x - o2.x 방식을 사용하면 정수 오버플로우가 발생한 경우 다른 결과를 도출하기 때문에 Integer.compare() 방식이 안전하다</p>
<p>  <br><br></p>
<ul>
<li>문자열(String 비교 방식)</li>
</ul>
<pre><code class="language-java">@Override
public int compare(Student o1, Student o2) {
    return o1.getName().compareTo(o.getName());
}</code></pre>
<p>⇒ 문자열은 숫자 타입이 아니기 때문에 빼기 연산(-)이 불가능하다. 따라서 문자열끼리 비교하기 위해서는 compareTo() 메서드를 사용하면 된다. (기존에 클래스에서 오버라이딩 했던 compareTo() 메서드와는 별개의 Stirng 비교 메서드이다.)</p>
<p><a href="https://velog.io/@faulty337/Java%EC%9D%98-Collection-%EC%A0%95%EB%A0%AC-%EB%B0%A9%EB%B2%95">https://velog.io/@faulty337/Java%EC%9D%98-Collection-%EC%A0%95%EB%A0%AC-%EB%B0%A9%EB%B2%95</a></p>
<p>  <br><br><br><br><br></p>
<h3 id="참고">참고)</h3>
<h3 id="🚀-더-세련된-최신-방식-java-8">🚀 더 세련된 최신 방식 (Java 8+)</h3>
<ul>
<li><strong>학번으로 정렬할 때</strong></li>
</ul>
<pre><code class="language-java">Collections.sort(list, Comparator.comparingInt(Student::getStudentNo));</code></pre>
<ul>
<li><strong>이름으로 정렬할 때</strong></li>
</ul>
<pre><code class="language-java">Collections.sort(list, Comparator.comparing(Student::getName));</code></pre>
<p>이 방식은 내부적으로 알아서 <code>Integer.compare</code>나 <code>String.compareTo</code>를 호출해주기 때문에 실수할 확률이 줄어든다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Stack & Queue & Deque]]></title>
            <link>https://velog.io/@l-suyeon-l/Stack-Queue-Deque</link>
            <guid>https://velog.io/@l-suyeon-l/Stack-Queue-Deque</guid>
            <pubDate>Sun, 01 Feb 2026 04:42:25 GMT</pubDate>
            <description><![CDATA[<h3 id="왜-stack-대신-deque를-쓸까">왜 Stack 대신 Deque를 쓸까?</h3>
<p><strong>1. 상속의 문제</strong>
: Stack은 Vector 클래스를 상속받는데, 이 때문에 Stack의 LIFO 원칙에 맞지 않게 인덱스로 중간의 값을 수정하거나 삭제하는 것이 가능해짐.</p>
<p><strong>2. 성능의 문제</strong>
: Stack은 모든 메서드에 synchronized되어 있어 멀티스레드 환경이 아닌 일반적인 싱글스레드 코딩테스트 환경에서는 성능이 느림</p>
<p><strong>3. 공식 문서의 권고</strong>
: Java 공식 문서에서도 ‘Stack 구조가 필요하다면 Stack 클래스 대신 ArrayDeque를 사용하라’고 명시되어 있음</p>
<br>
<br>

<p><strong>Stack / Queue / Deque 선언 방법</strong></p>
<pre><code class="language-java">// stack
Deque&lt;Integer&gt; stack = new ArrayDeque();

// queue
Deque&lt;Integer&gt; queue = new ArrayDeque();
Queue&lt;Integer&gt; queue = new ArrayDeque();  // Queue의 기능을 강조하고 싶을 때 사용

// deque
Deque&lt;Integer&gt; deque = new ArrayDeque();</code></pre>
<br>
<br>

<p><strong>Stack / Queue / Deque 사용 방법</strong></p>
<pre><code class="language-java">stack.push();    // 데이터 삽입
stack.pop();     // Last 데이터 추출
stack.peek();    // Last 데이터 확인

queue.offer();   // 데이터 삽입
queue.poll();    // First 데이터 추출
queue.peek();    // First 데이터 확인</code></pre>
<p><strong>** 참고</strong>
: ArrayDeque에서 push()는 내부적으로 addFirst()를 호출하고, pop()은 removeFirst()를 호출함(Stack). offer()은 addLast()를 호출하고, poll()은 removeFirst()를 호출함.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TreeSet & TreeMap]]></title>
            <link>https://velog.io/@l-suyeon-l/TreeSet-TreeMap</link>
            <guid>https://velog.io/@l-suyeon-l/TreeSet-TreeMap</guid>
            <pubDate>Sun, 01 Feb 2026 04:40:35 GMT</pubDate>
            <description><![CDATA[<h2 id="treeset">TreeSet</h2>
<br>

<p><strong>TreeSet이란?</strong></p>
<ul>
<li>Set의 성질을 그대로 상속받는 Tree 데이텉</li>
<li>이진 탐색 트리(Binary Search Tree)의 구조로 이루어져 있음</li>
<li>이진 탐색 트리 형태로 데이터를 저장하기에 nature ordering을 지원함</li>
<li>생성자 매개변수로 Comparator 객체를 입력해 정렬 방법을 임의로 지정 가능함</li>
</ul>
<p><strong>** 이진 탐색 트리(Binary Search Tree)</strong></p>
<ul>
<li>데이터 정렬, 검색에 높은 성능을 보이는 자료구조</li>
<li>데이터 추가, 삭제에는 시간이 소요됨</li>
</ul>
<p><img src="https://velog.velcdn.com/images/l-suyeon-l/post/274f25fd-486d-487b-9718-c2c08f2bd5b3/image.png" alt=""></p>
<ul>
<li>TreeSet은 이진 탐색 트리 중에서도 성능을 향상시킨 <strong>레드-블랙 트리</strong>로 구현됨
⇒ <strong>레드 블랙 트리</strong> : 부모 노드보다 작은 값을 가지는 왼쪽 자식으로, 큰 값을 가지는 노드는 오른쪽 자식으로 배치하여 데이터 추가, 삭제 시 트리가 한 쪽으로 치우쳐지지 않도록 균형을 맞춤</li>
</ul>
<br>

<p><img src="https://velog.velcdn.com/images/l-suyeon-l/post/e3445a63-e3f4-4833-8027-3de9b1ab62df/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/l-suyeon-l/post/3b3c9c08-543d-4f78-895a-1712486f01d1/image.png" alt=""></p>
<br>
<br>

<p><strong>TreeSet 생성</strong></p>
<pre><code class="language-java">import java.util.TreeSet;

TreeSet&lt;Integer&gt; tset = new TreeSet&lt;&gt;();</code></pre>
<br>


<p><strong>TreeSet 메서드</strong></p>
<pre><code class="language-java">// 요소 값 추가
tset.add(5);
tset.add(3);
tset.add(9);
tset.add(7);

System.out.println(tset);    // [3, 5, 7, 9]

// 요소 값 삭제
tset.remove(5);
System.out.println(tset);    // [3, 7, 9]

// tree set의 크기
tset.size();

// tree set의 최소값
tset.first();

// tree set의 최대값
tset.last();</code></pre>
<br>

<p><strong>TreeSet의 내림차순 정렬</strong>
: Comparator 객체를 이용해 정렬 방법 설정</p>
<pre><code class="language-java">TreeSet&lt;Integer&gt; tset = new TreeSet&lt;&gt;(Comparator.reverseOrder());

tset.add(5);
tset.add(3);
tset.add(9);

System.out.println(tset);    // [9, 5, 3]</code></pre>
<br>
<br>

<h2 id="treemap">TreeMap</h2>
<br>

<p><strong>TreeMap이란?</strong></p>
<ul>
<li>TreeSet과 동일하게 이진 탐색 트리 형태로 데이터 저장</li>
<li>Map 특성을 사용하기 때문에 key와 value로 이루어진 entry 객체 형태로 저장</li>
<li>key를 추가하면 정렬됨</li>
</ul>
<br>

<p><strong>TreeMap 생성</strong></p>
<pre><code class="language-java">import java.util.TreeMap;

TreeMap&lt;Integer, String&gt; tmap = new TreeMap&lt;&gt;();</code></pre>
<br>

<p><strong>TreeMap 메서드</strong></p>
<pre><code class="language-java">// 요소 값 추가
tmap.put(1, &quot;부산&quot;);
tmap.put(2, &quot;인천&quot;);
tmap.put(3, &quot;대구&quot;);
tmap.put(4, &quot;대전&quot;);
tmap.put(5, &quot;광주&quot;);

System.out.println(tmap);    // {1=부산, 2=인천, 3=대구, 4=대전, 5=광주, 6=울산}

// 요소 값 삭제
tmap.remove(1);

// tree set 크기
tmap.size();

// 요소 값 찾기
tmap.get(1);    // 부산

// key 값만 추출(중복X)
tmap.keySet();</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[HashMap & HashSet]]></title>
            <link>https://velog.io/@l-suyeon-l/HashMap-HashSet</link>
            <guid>https://velog.io/@l-suyeon-l/HashMap-HashSet</guid>
            <pubDate>Sun, 01 Feb 2026 04:38:07 GMT</pubDate>
            <description><![CDATA[<h2 id="hashmap">HashMap</h2>
<br>

<p><strong>HashMap이란?</strong></p>
<ul>
<li>key와 value로 구성되어 있는 순서쌍</li>
<li>key는 중복을 허용하지 않고, value는 중복을 허용함</li>
<li>요소의 저장 순서가 없음</li>
</ul>
<br>

<p><strong>HashMap의 생성</strong></p>
<pre><code class="language-java">HashMap&lt;String, String&gt; map = new HashMap&lt;&gt;();</code></pre>
<br>

<p><strong>HashMap 메서드</strong></p>
<pre><code class="language-java">// key &amp; value 추가
map.put(&quot;people&quot;, &quot;사람&quot;);
map.put(&quot;baseball&quot;, &quot;야구&quot;);

// key에 대한 value 값 추출
map.get(&quot;people&quot;);    // 사람

// key 값에 해당되는 아이템(key, value) 삭제
map.remove(&quot;people&quot;);    // 사람

// map의 크기
map.size()

// key 값만 추출(중복x) : Set&lt;key 자료형&gt; 반환
map.keySet();

// value 값만 추출(중복o) : Collection&lt;value 자료형&gt; 반환
map.values();

// key값/value값이 존재하는지 여부
map.containsKey(&quot;people&quot;);    // false
map.containsValue(&quot;야구&quot;);    // true</code></pre>
<br>

<p><strong>HashMap의 정렬</strong></p>
<ul>
<li>HashMap을 다루다 보면 HashMap을 특정 기준에 맞춰 정렬해야 할 경우가 있다. HashMap은 동시에 두 개의 데이터를 다루기 때문에 정렬 방식이 다양하고 복잡하기 때문에 자세히 공부할 필요가 있다.</li>
</ul>
<br>

<p><strong>① Key 값을 기준으로 정렬</strong></p>
<ul>
<li>HashMap의 keySet 메서드를 이용하여 List 컬렉션에 담음</li>
<li>오름차순 시 Collection.sort(), 내림차순 시 Collection.reverse() 사용</li>
</ul>
<pre><code class="language-java">HashMap&lt;String, Integer&gt; map = new HashMap&lt;&gt;();

map.put(&quot;A&quot;, 10);
map.put(&quot;B&quot;, 20);
map.put(&quot;C&quot;, 30);
map.put(&quot;D&quot;, 40);

List&lt;String&gt; keySet = new ArrayList&lt;&gt;(map.keySet());

// key 값으로 오름차순 정렬
Collection.sort(keySet);        // A B C D
// key 값으로 내림차순 정렬
Collections.reverse(keyset);    // D C B A</code></pre>
<p><strong>② Value 값을 기준으로 정렬</strong></p>
<ul>
<li>HashMap의 keySet 메서드를 이용하여 List 컬렉션에 담음</li>
<li>comparator을 사용하여 정렬</li>
<li>comparator은 람다 표현식으로 간단하게 표현할 수 있음</li>
</ul>
<pre><code class="language-java">HashMap&lt;String, Integer&gt; map = new HashMap&lt;&gt;();

map.put(&quot;A&quot;, 10);
map.put(&quot;B&quot;, 20);
map.put(&quot;C&quot;, 30);
map.put(&quot;D&quot;, 40);

List&lt;String&gt; keySet = new ArrayList&lt;&gt;(map.keySet());

// value 값으로 오름차순 정렬
keySet.sort(new Comparator&lt;String&gt;() {

    @Override
    public int compare(String o1, String o2) {
        return map.get(o1).compareTo(map.get(o2));
    }
});

// value 값으로 내림차순 정렬
keySet.sort((o1, o2) -&gt; {map.get(o2).compareTo(map.get(o2))};</code></pre>
<p><strong>주의)</strong> compareTo의 앞 뒤 파라미터에는 참조형 변수만 접근 가능</p>
<br>
<br>
<br>

<h2 id="hashset">HashSet</h2>
<br>

<p><strong>HashSet이란?</strong></p>
<ul>
<li>Set의 성질을 그대로 상속받는 Hash 데이터</li>
<li>자료의 순서가 없음</li>
<li>중복 값이 허용되지 않음</li>
<li>null 값을 허용</li>
</ul>
<br>

<p><strong>HashSet의 생성</strong></p>
<pre><code class="language-java">HashSet&lt;String&gt; set = new HashSet&lt;&gt;();</code></pre>
<br>

<p><strong>HashSet 메서드</strong></p>
<pre><code class="language-java">// 요소 값 추가
set.add(&quot;tiger&quot;);

// 요소 값 삭제
set.remove(&quot;tiger&quot;);

// set의 크기
set.size();

// 요소 값 검색
set.contains(&quot;lion&quot;);    // false</code></pre>
<ul>
<li><strong>HashSet의 add 메서드</strong>
: 추가하는 요소가 내부에 존재하지 않는다면 값을 추가하고 true 반환
내부에 존재한다면 false 반환</li>
<li><strong>HashSet의 remove 메서드</strong>
: 추가하는 요소가 내부에 존재한다면 값을 삭제하고 true 반환
내부에 존재하지 않는다면 false 반환</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[배열 & ArrayList]]></title>
            <link>https://velog.io/@l-suyeon-l/%EB%B0%B0%EC%97%B4-ArrayList</link>
            <guid>https://velog.io/@l-suyeon-l/%EB%B0%B0%EC%97%B4-ArrayList</guid>
            <pubDate>Sat, 24 Jan 2026 15:15:03 GMT</pubDate>
            <description><![CDATA[<h2 id="배열">배열</h2>
<p><strong>특징</strong></p>
<ul>
<li>배열의 크기(길이)는 변경할 수 없음.
⇒ 정적 할당(static allocation), 불변(immutable)</li>
<li>데이터가 메모리에 연속적으로 나열되어 있기 때문에 인덱스를 통한 접근 속도가 빠름</li>
<li>인덱스를 통해 데이터를 삭제하더라도 해당 위치는 빈 공간으로 계속 남음</li>
</ul>
<br>

<p><strong>배열의 선언</strong></p>
<pre><code class="language-java">int[] points = new int[3];
int[] points2 = new int[] {1, 3, 5};
int[] points3 = {1, 3, 5}</code></pre>
<br>

<p><strong>배열의 순회</strong></p>
<ul>
<li>for문</li>
</ul>
<pre><code class="language-java">for(int i = 0; i &lt; intArry.length; i++) {
    int x = intArray[i];
    System.out.println(x);
}</code></pre>
<ul>
<li>for-Each문</li>
</ul>
<pre><code class="language-java">for(int x : intArray) {
    System.out.println(x);
}</code></pre>
<p><br><br></p>
<h3 id="배열의-api-활용--arrays">배열의 API 활용 : Arrays</h3>
<br>

<ul>
<li>배열 정렬</li>
</ul>
<pre><code class="language-java">int[] arry = {10, 5, 8, 20, 3};
Arrays.sort(arry);    // {3, 5, 8, 10, 20}</code></pre>
<br>

<ul>
<li>배열의 최댓값</li>
</ul>
<pre><code class="language-java">int[] arry = {10, 5, 8, 20, 3};
int max = Arrays.stream(arry).max().getAsInt();    // 20</code></pre>
<br>

<ul>
<li>배열의 최솟값</li>
</ul>
<pre><code class="language-java">int[] arry = {10, 5, 8, 20, 3};
int max = Arrays.stream(arry).min().getAsInt();    // 3</code></pre>
<br>

<ul>
<li>배열의 복사</li>
</ul>
<pre><code class="language-java">int[] arry = {10, 5, 8, 20, 3};
int[] copy = Arrays.copyOf(arry, arry.length);    // 배열 그대로 복사
int[] copyExtends = Arrays.copyOf(arry, 5);       // 배열 크기를 늘려서 복사</code></pre>
<p>⇒ 원본 배열은 변경되지 않고 새로운 배열 객체를 생성
⇒ 배열 크기를 늘린 경우 기본형 배열은 0, 객체 배열은 null로 채워짐
<br><br></p>
<p><strong>** Arrays.copyOf()와 System.arraycopy()</strong></p>
<ul>
<li>System.arraycopy(원본배열, 원본 배열 복사 시작 인덱스, 새배열, 새배열의 복사 시작 인덱스, 복사할 요소 개수)</li>
<li>Arrays.copyOf(원본배열, 원본 배열에서 복사해올 길이)</li>
</ul>
<p>⇒ Arrays.copyOf는 System.arraycopy를 래핑한 함수임. 즉, 동일한 기능을 함. 하지만, Arrays.copyOf가 조금 더 직관적이라 더 많이 사용됨 </p>
<p><br><br></p>
<h3 id="다차원-배열-순회탐색">다차원 배열 순회/탐색</h3>
<blockquote>
<p>다차원(특히 2차원) 배열에서 상하좌우의 값을 탐색하는 경우 <strong>delta</strong> 배열을 이용하여 탐색하면 효율적임</p>
</blockquote>
<ul>
<li>좌/우 탐색
delta = {(0, -1), (0, 1)}</li>
<li>상/하 탐색
delta = {(-1, 0), (1, 0)}</li>
<li>4방 탐색
delta = {(-1, 0), (0, -1), (0, 1), (1, 0)}</li>
<li>8방 탐색
delta = {(-1, -1), (-1, 0), (1, 0), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)}</li>
</ul>
<p><br><br></p>
<h2 id="collection--arraylist">Collection : ArrayList</h2>
<p><strong>특징</strong></p>
<ul>
<li>리스트의 길이는 가변적임
⇒ 동적 할당(dynamic allocation), 가변(mutable)</li>
<li>데이터가 메모리에 연속적으로 나열되어 있지 않기 때문에 인덱스를 통한 접근 속도가 비교적 느림</li>
<li>데이터가 삭제되면 해당 공간은 삭제됨</li>
</ul>
<br>

<p><strong>ArrayList의 생성</strong></p>
<pre><code class="language-java">// 기본 생성
ArrayList&lt;Integer&gt; list1 = new ArrayList&lt;&gt;();

// 초기 용량(capacity) 지정
ArrayList&lt;Integer&gt; list2 = new ArrayList&lt;&gt;(10);

// 배열을 넣어 생성
ArrayList&lt;Integer&gt; list3 = new ArrayList&lt;&gt;(Arrays.asList(1, 2, 3));</code></pre>
<br>

<p><strong>ArrayList의 추가</strong></p>
<pre><code class="language-java">ArrayList&lt;Integer&gt; list1 = new ArrayList&lt;&gt;();

list1.add(1);    // {1}
list1.add(2);    // {1, 2}
list1.add(3);    // {1, 2, 3}</code></pre>
<ul>
<li>addAll() 메서드<pre><code class="language-java">ArrayList&lt;String&gt; list1 = new ArrayList&lt;&gt;(Arrays.asList(1, 2));
ArrayList&lt;String&gt; list2 = new ArrayList&lt;&gt;(Arrays.asList(3, 4));
</code></pre>
</li>
</ul>
<p>list1.addAll(list2);    // list1에 list2의 내용 추가</p>
<pre><code>
⇒ 컬렉션 자체를 ArrayList에 추가할 수 있음

&lt;br&gt;

**ArrayList의 삭제**

```java
ArrayList&lt;String&gt; list1 = new ArrayList&lt;&gt;(Arrays.asList(1, 2));

// 1번째 인덱스 요소 삭제
list1.remove(1);    // {1}

// list1의 데이터 모두 삭제
list1.clear();</code></pre><br>

<p><strong>ArrayList의 검색</strong></p>
<pre><code class="language-java">ArrayList&lt;String&gt; list1 = new ArrayList&lt;&gt;(Arrays.asList(&quot;A&quot;, &quot;B&quot;, &quot;C&quot;));

// 특정 인덱스에 저장된 객체 반환
list1.get(1);    // B

// list에 A가 있는지 검색
list1.contains(&quot;A&quot;);    // true

// list에 A가 있는지 순차적으로 검색하고 index를 반환 (만일 없으면 -1)
list1.indexOf(&quot;A&quot;);    // 0</code></pre>
<br>

<p><strong>ArrayList의 요소 변경</strong></p>
<pre><code class="language-java">ArrayList&lt;String&gt; list1 = new ArrayList&lt;&gt;(Arrays.asList(&quot;A&quot;, &quot;B&quot;, &quot;C&quot;));

// 특정 인덱스 값을 설정값으로 변환
list1.set(1, &quot;D&quot;);    // {&quot;A&quot;, &quot;D&quot;, &quot;C&quot;}</code></pre>
<br>

<p><strong>ArrayList의 크기</strong></p>
<pre><code class="language-java">ArrayList&lt;String&gt; list1 = new ArrayList&lt;&gt;(Arrays.asList(&quot;A&quot;, &quot;B&quot;, &quot;C&quot;));

list1.size();    // 3</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[완전 탐색1]]></title>
            <link>https://velog.io/@l-suyeon-l/%EC%99%84%EC%A0%84-%ED%83%90%EC%83%891</link>
            <guid>https://velog.io/@l-suyeon-l/%EC%99%84%EC%A0%84-%ED%83%90%EC%83%891</guid>
            <pubDate>Sat, 24 Jan 2026 11:18:58 GMT</pubDate>
            <description><![CDATA[<h2 id="완전-탐색">완전 탐색</h2>
<blockquote>
<p><strong>모든 가능한 경우의 수를 탐색</strong>하여 <strong>최적의 결과</strong>를 찾는 방법. 모든 가능성을 고려하기 때문에 경우의 수가 많은 경우 시간과 메모리 부담이 큼. 문제의 특성에 따라 다른 탐색 기법을 사용해야 함.</p>
</blockquote>
<br>

<p><strong>종류</strong></p>
<p><img src="https://velog.velcdn.com/images/l-suyeon-l/post/af6cc3c6-49c4-4bf3-94ea-5e31adfe9e80/image.png" alt=""></p>
<p><strong>시간 복잡도</strong></p>
<blockquote>
<p>비트마스크 &gt; DFS/BFS &gt; Brute-Force &gt; 재귀함수 &gt; 순열 &gt; 백트래킹</p>
</blockquote>
<br>

<p><a href="https://adjh54.tistory.com/196">참고 문서</a>
<a href="https://adjh54.tistory.com/197?category=1085769">추가 자료</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Two Pointers & Sliding Window 알고리즘]]></title>
            <link>https://velog.io/@l-suyeon-l/Two-Pointers-Sliding-Window-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@l-suyeon-l/Two-Pointers-Sliding-Window-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Sat, 24 Jan 2026 11:18:15 GMT</pubDate>
            <description><![CDATA[<h2 id="구간-합prefix-sum">구간 합(Prefix Sum)</h2>
<blockquote>
<p>배열의 0번째 인덱스부터 특정 구간까지의 합을 새로운 배열로 정의하는 것. 선형 탐색 대신 구간 합 계산 방식으로 시간 복잡도를 줄임</p>
</blockquote>
<br>

<p><strong>특징</strong></p>
<ul>
<li>배열 A에 대해 합 배열 S를 정의</li>
<li>합 배열 S[i]는 배열 A의 0번째 원소부터 i번째 원소까지의 합에 대한 정보를 담음
⇒ S[i] = A[0] + A[1] + A[2] + … + A[i-1] + A[i]</li>
<li>합 배열을 통해 선형 탐색을 할 필요가 없어지고 시간 복잡도가 O(1)로 줄어듦</li>
</ul>
<br>

<p><strong>구현 방식</strong></p>
<ul>
<li>S[i] = S[i-1] + A[i]</li>
</ul>
<br>

<p><strong>특정 구간(i~j)의 구간 합 구하기</strong></p>
<ul>
<li>S[j] - S[i-1]</li>
</ul>
<br>

<p><a href="https://krchoish.tistory.com/11?category=1104926">참고 문서</a></p>
<p><br><br></p>
<h2 id="two-pointers-알고리즘">Two Pointers 알고리즘</h2>
<blockquote>
<p>배열이나 리스트에서 <strong>두 개의 포인터(인덱스)</strong>를 사용하여 <strong>특정 조건을 만족하는 부분 구간</strong>을 효율적으로 탐색하는 알고리즘. 일반적으로 배열이나 리스트가 <strong>정렬</strong>되어 있을 때 사용</p>
</blockquote>
<br>

<p><strong>특징</strong></p>
<ul>
<li><p>왼쪽 포인터 &amp; 오른쪽 포인터를 사용. 이들은 각각 탐색 범위의 시작과 끝을 가리킴</p>
</li>
<li><p>왼쪽 포인터를 고정한 상태에서 오른쪽 포인터를 이동하여 탐색하는 방식</p>
</li>
<li><p>두 개의 포인터를 적절히 이동시키며 시간 복잡도를 최적화할 수 있음</p>
</li>
<li><p>(1) 특정 배열 내에 target 값과 같거나 유사한 <strong>부분 합</strong>이 몇 개 존재하는지 계산</p>
</li>
<li><p>(2) 배열 내 <strong>target = arr[i] + arr[j]</strong>를 만족하는 (i, j) 쌍이 몇 개 존재하는지 계산</p>
</li>
<li><p>중첩 반복문의 시간 복잡도 : <strong>O(N²)</strong></p>
</li>
<li><p>투 포인터의 시간 복잡도 : <strong>O(N)</strong></p>
</li>
</ul>
<br>

<p><strong>실행 과정</strong></p>
<p>조건)</p>
<ul>
<li>두 포인터 start와 end는 0에서부터 시작</li>
<li>항상 start ≤ end를 만족</li>
<li>start와 end가 배열의 크기(N)에 도달하면 알고리즘이 끝남</li>
<li>start와 end 사이의 부분 합을 S라고 가정</li>
<li>부분 합이 M인 경우의 수를 cnt라고 가정</li>
</ul>
<p>구현)</p>
<ul>
<li>S &gt; M혹은 end == N : start++</li>
<li>S &lt; M : end++</li>
<li>S == M : cnt++</li>
</ul>
<p><br><br></p>
<h2 id="sliding-window-알고리즘">Sliding Window 알고리즘</h2>
<blockquote>
<p>투 포인터 알고리즘과 유사. 배열이나 리스트에서 <strong>특정 길이의 특정 조건을 만족하는 구간</strong>을 효율적으로 탐색하는 알고리즘. 구간의 넓이가 일정하기 때문에 포인터가 2개일 필요가 없음</p>
</blockquote>
<br>

<p><strong>특징</strong></p>
<ul>
<li><p>핵심은 “중복된 데이터를 다시 계산하지 않고 재사용하는 것”</p>
</li>
<li><p>교집합의 정보는 공유하고, 양쪽 끝 원소만 갱신</p>
</li>
<li><p>(1) 고정 크기 구나 합의 최댓값/최솟값 찾기</p>
</li>
<li><p>(2) 문자열 패턴 탐색 : 아나그램 찾기</p>
</li>
<li><p>중첩 반복문의 시간 복잡도 : <strong>O(N²)</strong></p>
</li>
<li><p>슬라이딩 윈도우의 시간 복잡도 : <strong>O(N)</strong></p>
</li>
</ul>
<br>

<p><strong>실행 과정</strong></p>
<p>조건)</p>
<ul>
<li>배열의 구간 길이를 N이라고 가정</li>
</ul>
<p>구현)</p>
<ul>
<li>배열의 길이가 N인 첫 번째 구간의 부분 합 계산</li>
<li>첫번째 구간의 부분 합에서 맨 처음 배열 값을 빼고, 마지막 배열 값을 더함</li>
</ul>
<p><br><br></p>
<h3 id="two-pointers-알고리즘과-sliding-window-알고리즘의-핵심">Two Pointers 알고리즘과 Sliding Window 알고리즘의 핵심</h3>
<blockquote>
<p>시간 복잡도를 많이 차지하는 중첩 반복문이 아닌, start&amp;end 포인터를 활용해 O(N)의 시간 복잡도 알고리즘을 구현하는 것</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[문자열 String]]></title>
            <link>https://velog.io/@l-suyeon-l/%EB%AC%B8%EC%9E%90%EC%97%B4-String</link>
            <guid>https://velog.io/@l-suyeon-l/%EB%AC%B8%EC%9E%90%EC%97%B4-String</guid>
            <pubDate>Sat, 24 Jan 2026 03:15:09 GMT</pubDate>
            <description><![CDATA[<h2 id="bufferedreader">BufferedReader</h2>
<br>

<p><strong>BufferedReader 사용법</strong></p>
<pre><code class="language-java">BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str = br.readLine();
StringTokenizer st = new StringTokenizer(str);</code></pre>
<p><strong>특징</strong></p>
<ul>
<li>readLine()의 리턴 값은 String</li>
<li>main에 throws IOException 예외 처리를 해줘야 함</li>
<li>readLine()은 입력을 line 단위로 읽어옴
⇒ 공백 단위로 데이터를 가공하려면 nextToken()을 사용해야 함
⇒ 새로운 line을 받아오려면 다시 readLine() 해야 함</li>
</ul>
<br>

<p><strong>BufferedReader란?</strong></p>
<blockquote>
<p>데이터를 한 번에 읽어와 버퍼에 보관한 후 버퍼에서 데이터를 읽어오는 방식으로 동작하는 클래스. 즉, 사용자가 입력한 문자 스트림은 읽는 것(read)이다.</p>
</blockquote>
<ul>
<li><strong>buffer</strong> : 데이터를 한 곳에서 다른 한 곳으로 전송하는 동안 일시적으로 해당 데이터를 보관하는 임시 메모리 영역</li>
</ul>
<br>

<p><strong>InputStreamReader란?</strong></p>
<blockquote>
<p>문자 기반의 보조 스트림으로써 바이트 기반 스트림을 문자 기반 스트림으로 연결시켜 주는 역할을 한다</p>
</blockquote>
<br>

<p><strong>System.in이란?</strong></p>
<blockquote>
<p>사용자로부터 입력을 받기 위한 입력 스트림. Scanner 클래스뿐만 아니라 다른 입력 클래스들도 System.in을 통해 사용자 입력을 받아야 한다</p>
</blockquote>
<br>

<p><strong>StringTokenizer란?</strong></p>
<blockquote>
<p>문자열을 지정한 구분자로 쪼개주는 클래스. 쪼개어진 문자열을 ‘토큰(Token)’이라고 한다.</p>
</blockquote>
<br>

<h3 id="scanner와-차이점"><strong>Scanner와 차이점</strong></h3>
<p><strong>1. 타입(Type)</strong></p>
<ul>
<li>BufferedReader : readLine() 함수를 통해 String 형식으로만 입력받음. 형 변환을 위해 추가적인 코드 작성 필요</li>
<li>Scanner : nextInt(), nextDouble()과 같은 함수로 입력 값을 원하는 타입으로 읽고 파싱할 수 있음</li>
</ul>
<p><strong>2. 메모리 용량</strong></p>
<ul>
<li>BufferedReader : 버퍼 메모리 8KB. 많은 입력이 있을 경우 Scanner보다 효율적. 하지만 초기에 큰 메모리를 사용하게 됨</li>
<li>Scanner : 버퍼 메모리 1KB</li>
</ul>
<p><strong>3. Thread-safe</strong></p>
<ul>
<li>BufferedReader : Thread-safe. 멀티 스레드 환경에서 안전함. 스레드 간 입력 값을 공유할 수 있음</li>
<li>Scanner : Thread-unsafe.</li>
</ul>
<p><strong>4. 실행 속도</strong></p>
<ul>
<li>BufferedReader : 입력 값을 줄 별로 버퍼에 담아두고 처리하여 효율적임</li>
<li>Scanner : 문자가 입력될 때마다 입출력을 처리하여 비효율적임</li>
</ul>
<br>
<br>

<h2 id="입력받은-토큰string-형-변환"><strong>입력받은 토큰(String) 형 변환</strong></h2>
<p><strong>1. String ⇒ Number</strong></p>
<pre><code class="language-java">int n = Integer.parseInt(st.nextToken());
float n = Float.parseFloat(st.nextToken());
double n = Double.parseDouble(st.nextToken());</code></pre>
<br>

<p><strong>2. String ⇒ char</strong></p>
<p><strong>charAt(i)</strong> : 문자열의 i번째 char를 반환하는 메서드</p>
<pre><code class="language-java">String str = st.nextToken();    // &quot;Hello&quot;
for(int i = 0; i &lt; str.length(); i++) {
    char ch = str.charAt(i);
    System.out.println(ch);
}</code></pre>
<p><strong>toCharArray()</strong> : 문자열을 char 배열로 변환</p>
<pre><code class="language-java">String str = st.nextToken();
for(char ch : str.toCharArray()) {    // for-Each문으로 바로 탐색 가능
    System.out.println(ch);
}</code></pre>
<br>

<p><strong>번외) String형으로 변환</strong></p>
<p><strong>valueOf()</strong> : 괄호 안의 객체를 문자열로 변환</p>
<pre><code class="language-java">int n = 1;
double d = 3.14;
char c = &#39;a&#39;;
boolean b = true;

String str1 = String.valueOf(n);    // &quot;1&quot;
String str2 = String.valueOf(d);    // &quot;3.14&quot;
String str3 = String.valueOf(c);    // &quot;a&quot;
String str4 = String.valueOf(b);    // &quot;true&quot;</code></pre>
<ul>
<li>기본형(primitive type)을 Wrapper 클래스 객체로도 변환할 수 있음</li>
</ul>
<pre><code class="language-java">int n = 1;
Integer num = Integer.valueOf(n);    // Integer 객체 1

double d = 3.14;
Double dnum = Double.valueOf(d);    // Double 객체 3.14</code></pre>
<br>

<p><strong>toString()</strong> : 괄호 안의 객체를 문자열로 변환</p>
<pre><code class="language-java">int n = 1;
double d = 3.14;
char c = &#39;a&#39;;
boolean b = true;

String str1 = Integer.toString(n);      // &quot;1&quot;
String str2 = Double.toString(d);       // &quot;3.14&quot;
String str3 = Character.toString(c);    // &quot;a&quot;
String str4 = Boolean.toString(b);      // &quot;true&quot;</code></pre>
<br>
<br>

<h2 id="string-메서드">String 메서드</h2>
<p><strong>문자열 길이</strong></p>
<pre><code class="language-java">String str = &quot;Hello&quot;;
int len = str.length();    // 5</code></pre>
<br>

<p><strong>문자열 연결</strong></p>
<pre><code class="language-java">String str1 = &quot;Hello&quot;;
String str2 = &quot;World&quot;;
String res = str1 + &quot; &quot; + str2;    // Hello World</code></pre>
<br>

<p><strong>문자열 잘라내기</strong></p>
<pre><code class="language-java">String str = &quot;Hello World&quot;;
String res = str.substring(0,5);    // Hello</code></pre>
<br>

<p><strong>문자열 비교하기</strong></p>
<pre><code class="language-java">// String Pool에 저장(literal 할당)
String str1 = &quot;Hello&quot;;
String str2 = &quot;Hello&quot;;
System.out.println(str1 == str2);        // true
System.out.println(str1.equals(str2));   // true

// Heap에 저장(생성자 할당)
String str3 = new String(&quot;Hello&quot;);
String str4 = new String(&quot;Hello&quot;);
System.out.println(str3 == str4);        // false
System.out.println(str3.equals(str4);    // true</code></pre>
<br>
<br>

<h2 id="stringbuilder--stringbuffer">StringBuilder / StringBuffer</h2>
<ul>
<li>‘+’을 통해 String을 연결하게 되면, 메모리에 새로운 주소를 할당하여 메모리 낭비가 발생함
⇒ StringBuilder/StringBuffer는 내부 메서드를 통해 메모리 낭비를 최소화할 수 있음</li>
</ul>
<pre><code class="language-java">StringBuilder sb = new StringBuilder();

// append()
sb.append(&quot;Hello&quot;);    // Hello
sb.append(&quot;World&quot;);    // Hello World

// substring(start, end)
sb.substring(0, 5);    // Hello

// delete(start, end)
sb.delete(6, 11);      // Hello 

// insert(offset, str)
sb.insert(6, &quot;Java&quot;);  // Hello Java

// toString()
String str = sb.toString();</code></pre>
<p>→ StringBuffer도 사용법은 동일함</p>
<br>

<h3 id="stringbuilder와-stringbuffer의-차이점">StringBuilder와 StringBuffer의 차이점</h3>
<ul>
<li><strong>StringBuilder</strong> : 문자열 파싱 성능이 우수함. 하지만 동기화를 지원하지 않아 멀티 스레드 환경보다 단일 스레드 환경에서 더 적합함. 코딩테스트의 경우 더 빠른 StringBuilder가 선호됨</li>
<li><strong>StringBuffer</strong> : 멀티 스레드 환경에서 안전함. 하지만 속도가 느림</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데이터리안 부트캠프] Retention]]></title>
            <link>https://velog.io/@l-suyeon-l/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%A6%AC%EC%95%88-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84</link>
            <guid>https://velog.io/@l-suyeon-l/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%A6%AC%EC%95%88-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84</guid>
            <pubDate>Thu, 09 Oct 2025 04:10:04 GMT</pubDate>
            <description><![CDATA[<p>&amp;nbsp9월 한 달이 지나고 10월, 데이터리안 부트캠프 실전반을 수강하고 있다. 현재 Week 1인데 Subquery가 상당히 복잡하다. WHERE절 서브쿼리, FROM절 서브쿼리, SELECT절 서브쿼리 등등... 하지만 논리적으로 생각하여 코드를 구현하면 생각한 대로 결과가 나와서 꽤나 재미있다.</p>
<p>&amp;nbsp이제 Week 2로 들어갈 차례인데, 본격적으로 데이터 분석을 시작하는 것 같다. <strong>&#39;리텐션&#39;</strong> 에 대해 배운다고 한다. 이 리텐션에 관련한 글을 읽고 감상을 작성해보도록 하겠다.</p>
<br/>
<br/>
먼저, Retention의 개념을 정확히 짚고 가겠다.

<p>&amp;nbsp입문반 4주차, 우리는 매출 분석이론으로 &#39;AARRR&#39; 방법론을 배웠다. AARRR은 서비스 성장 분석 방법론 중 하나인데, 매출이 증가 혹은 감소했을 때 이 원인이 무엇인가?를 생각하는 데에 있어서 중요한 관점을 제공한다.</p>
<ul>
<li><strong>A</strong>cquisition (고객 유치) : 광고 등으로 새로운 고객을 유치하는 단계</li>
<li><strong>A</strong>ctivation (활성화) : 회원가입, 튜토리얼 등 고객을 활성화시키는 단계</li>
<li><strong>R</strong>etention (리텐션) : 지속적으로 서비스를 사용하게 만드는 단계</li>
<li><strong>R</strong>evenue (매출) : 매출을 만드는 단계</li>
<li><strong>R</strong>eferral (추천) : 기존 고객이 다른 고객에게 제품을 추천하는 단계</li>
</ul>
<br/>
&nbsp이 중에서도 Retention 단계가 사용자 유지와 관련한 지표를 계산하는 가장 중요한 단계이다.
<br/>
<br/>
<br/>

<p>&amp;nbsp&#39;롤링 리텐션&#39; 파트에서, 데이터분석을 하다 보면 시간이 지나면 데이터 숫자가 변하기 마련이고, 데이터를 다루지 않는 사람들은 이를 받아들이기 어려워한다 라는 부분이 있었다. 물론 저는 실무에서 일해 본 경험이 없지만, 충분히 겪을 수 있는 상황이고 나라면 어떻게 대처해야 할 지 고민이 됐다. 또, 데이터리안 멘토분들의 슬랙 대화에서 &#39;방어 로직&#39;을 넣으셨다고 했는데 이 또한 실무에 들어가면 해야 하는 부분이라고 생각하니 조금은 막막해진 것도 같다.</p>
<p>&amp;nbsp같은 데이터라도 활용하는 리텐션 방식에 따라서 결과 값이 달라지는 것은 당연하다. 하지만, 어떤 상황에서 어떤 방식을 활용해야 할지 또 주의점은 무엇인지 항상 궁금했다. 그런데 &#39;범위 리텐션&#39; 파트에서 이 부분을 확실히 짚어주셔서 드디어 궁금증이 해결되었다.</p>
<p>&amp;nbsp마지막 두 글은 상당히 난이도가 높았지만, 역시 데이터리안 블로그의 포스트에서는 양질의 지식을 얻어갈 수 있다는 것을 한 번 더 느꼈다. 간단한 데이터로 넓은 인사이트를 주고, 독자들이 이해하기 쉽게 풀어서 설명해준다. 물론, 내용 자체가 쉬운 내용은 아니기 때문에 두 번 세 번 반복해서 읽는다. 그러다보면, 데이터분석 이론은 내 것이 되어있다.</p>
<p><br/><br/>
학교 시험이랑 실전반 시기가 겹쳐서 조금은.. 힘든 하루하루를 보내고 있지만, 그래도 매일매일 열심히 수강해서 끝까지 수료하고 싶다! 포스트를 읽다 보니 GA4 데이터 분석 캠프도 수강해보고 싶기도 하고..</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Ubuntu에서 xv6 설치하기]]></title>
            <link>https://velog.io/@l-suyeon-l/Ubuntu%EC%97%90%EC%84%9C-xv6-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@l-suyeon-l/Ubuntu%EC%97%90%EC%84%9C-xv6-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 30 Sep 2025 05:40:42 GMT</pubDate>
            <description><![CDATA[<p>&amp;nbsp이번 학기 운영체제 수업을 듣고 있다. 재작년에 컴퓨터구조 수업을 들었을 때 너무 추상적이고 어려웠던 기억이 있다. 그래서 운영체제를 듣고 싶지 않았지만 전공 필수 과목이라 어쩔 수 없이 들었다. 하지만 컴퓨터구조 처럼 추상적이지도, 어렵지도 않은 것 같아서 재밌게 듣고 있다.</p>
<p>&amp;nbsp오늘은 교수님께서 주신 첫 번째 과제 <strong>xv6 Project</strong>에서 xv6 설치 과정에 대해 포스팅 해보겠다.</p>
<br/>
&nbsp들어가기에 앞서, 컴퓨터에는 Ubuntu 24.04 버전이 설치되어 있어야 한다. 나는 네트워크 프로그래밍 수업에서 이미 설치한 전적이 있어 따로 설치 과정을 거치지는 않았다. 우분투 설치는 구글에도 검색하면 많이 나오니 따로 검색해 보시길..

<p><br/><br/></p>
<h4 id="1-우분투-설치-확인하기">1. 우분투 설치 확인하기</h4>
<p><img src="https://velog.velcdn.com/images/l-suyeon-l/post/f5b7fbe8-039f-4727-9ff4-907ef1811ecf/image.png" alt=""></p>
<p>커맨드 창에</p>
<pre><code>wsl --list --online</code></pre><p>을 입력하면 위 사진처럼 리스트가 뜬다. 이 중 <strong>Ubuntu-24.04</strong> 파일이 있다면 우분투 설치가 되어 있는 것이다. 만약, 우분투 설치가 되어있지 않다면 <strong>Linux용 Windows 하위 시스템 설치되어 있지 않습니다.</strong> 라고 뜨면서 설치할 수 있는 커맨드가 나타나므로 보고 설치하면 된다.</p>
<p><br/><br/><br/></p>
<h4 id="2-우분투-환경으로-변경하기">2. 우분투 환경으로 변경하기</h4>
<p><img src="https://velog.velcdn.com/images/l-suyeon-l/post/871bcd6b-b4de-4fd9-a083-11ad044d4f04/image.png" alt=""></p>
<p>교수님께서 알려주신 설치를 진행하려면 우분투 환경으로 바꿔야하는데 어떻게 하지? 생각하다가 그냥 커맨드 창에</p>
<pre><code>ubuntu</code></pre><p>를 쳐봤다. 근데 바뀌었다. 얻어걸렸다. 얏호~</p>
<p><br/><br/><br/></p>
<h4 id="3-우분투-버전-정보-확인하기">3. 우분투 버전 정보 확인하기</h4>
<p><img src="https://velog.velcdn.com/images/l-suyeon-l/post/52680cc1-3c71-41f5-9a94-afcec0ceea1b/image.png" alt=""></p>
<pre><code>cat /etc/issue</code></pre><p>를 커맨드 창에 입력하면 우분투의 버전을 확인할 수 있다. <strong>cat</strong>가 뭔가 했더니 <strong>concatenate</strong>, 파일에 연결한다는 뜻이라고 한다.</p>
<p><br/><br/><br/></p>
<h4 id="4-패키지-설치하기">4. 패키지 설치하기</h4>
<p>&amp;nbsp여기서 시행착오가 있었다. GitHub에서 생성한 레포지토리의 SSH key를 가져와서 git clone을 해야되는데, 그 전에 패키지 설치를 해야한다. 그런데 자료를 제대로 안보고 바로 빌드를 해버려서 오류가 났다. 물론, 구글 검색을 해서 패키지는 바로 설치했지만 자료만 제대로 봤다면 바로 진행했을 텐데..</p>
<p>어쨌든 패키지를 설치하려면
<img src="https://velog.velcdn.com/images/l-suyeon-l/post/d10b5f01-55d5-443f-8c8e-64ed2c08bf8e/image.png" alt=""></p>
<pre><code>sudo apt update</code></pre><p>로 업데이트를 한 후,</p>
<p><img src="https://velog.velcdn.com/images/l-suyeon-l/post/5ad68825-c68b-4634-a9b0-909d3049932e/image.png" alt=""></p>
<pre><code>sudo apt install -y build-essential expect qemu-system-misc gcc-riscv64-unknown-elf</code></pre><p>를 입력하여 여러 패키지를 설치해준다.
물론 나는 이미 다 설치해놓은 상태여서 사진을 보면 알 수 있듯이, 이미 설치되어 있다고 뜬다. 내 커맨드 결과와 같지 않다고 해서 문제될 것은 없다. 에러만 뜨지 않으면 된다.</p>
<p><br/><br/><br/></p>
<h4 id="5-패키지-빌드하기">5. 패키지 빌드하기</h4>
<p>&amp;nbsp여기서 어려움을 겪었다. 1시간을 헤맸다. &#39;make&#39;, &#39;make qemu&#39; 커맨드를 입력하는데 오류가 많이 떴다... 일단 이 얘기는 뒤에 가서 하고</p>
<p><img src="https://velog.velcdn.com/images/l-suyeon-l/post/0ceea25b-276e-4dfa-b29d-0664f3100c02/image.png" alt=""></p>
<pre><code>git clone (SSH key 주소) p1
cd p1/xv6-riscv</code></pre><p>를 입력하여 깃을 클론해주고, 클론된 파일에 접근해준다.
해당 깃이 이미 클론되어 있어, 사진에는 이미 존재한다는 문구가 떴다.</p>
<p><img src="https://velog.velcdn.com/images/l-suyeon-l/post/881da2c3-bdef-432d-bd7d-2f1f67560b51/image.png" alt=""></p>
<pre><code>make</code></pre><p>위 커맨드를 입력해서 make 해주면 되는데(뭘 make 하는지는 몰겟다ㅋㅋ) </p>
<pre><code>Error: Couldn&#39;t find a riscv64 version of GCC/binutils.</code></pre><p>에러가 떴다.
ㅠㅠ</p>
<p>바로 구글에 검색하니 stackoverflow 페이지를 찾을 수 있었고, 답변에서 좋은 사이트를 찾았다.</p>
<p><a href="https://pdos.csail.mit.edu/6.828/2019/tools.html">https://pdos.csail.mit.edu/6.828/2019/tools.html</a></p>
<p>그리고 이 페이지에서 알려준대로</p>
<pre><code>riscv64-unknown-elf-gcc --version</code></pre><p>을 입력했더니 무언가가 설치 안됐다고, 명령어를 입력하라고 해서 설치를 완료 했다. 알고 보니 내가 자료를 읽지 않고 설치하지 않았던 패키지(4번 과정) 때문이었다. 그래서 이 포스트 순서대로 잘 따라오신 분들은 오류가 나지 않았을 것이다.</p>
<p><br/><br/>
이후</p>
<pre><code>make qemu</code></pre><p>를 입력했는데, qemu의 버전이 낮다고. 7.2.0 이상이어야 한다고 했다. 이것 또한 구글 검색과 제미나이의 도움을 받으며 30분 넘게 설치하고, 입력하고 했는데 도저히 7.2.0 이상 버전이 설치되지 않았다.. 왜지?
하라는 대로 다 했는데 안됐다.</p>
<pre><code>sudo apt update
sudo apt install build-essential zlib1g-dev libglib2.0-dev libpixman-1-dev
wget https://download.qemu.org/qemu-7.2.0.tar.xz
tar xf qemu-7.2.0.tar.xz
cd qemu-7.2.0</code></pre><p>여기까진 순조로웠다. 이후 &#39;./configure ...&#39; 어쩌구 하는 커맨드를 입력하고 설치할 것을 다 설치해도 qemu의 버전이 6.2에서 머물렀다. 그런데 아까 찾았던 페이지에서 qemu 설치 방법이 있길래 시도해봤다.</p>
<pre><code>./configure --disable-kvm --disable-werror --prefix=/usr/local --target-list=&quot;riscv64-softmmu&quot;
make
sudo make install
cd ..</code></pre><p>를 진행하고 (시간이 꽤 많이 걸린다)</p>
<pre><code>make qemu</code></pre><p>를 입력하니</p>
<p><img src="https://velog.velcdn.com/images/l-suyeon-l/post/d2c4b038-b657-4988-b031-a3b31037babc/image.png" alt=""></p>
<p>드디어 떴따!!</p>
<p><img src="https://velog.velcdn.com/images/l-suyeon-l/post/6b70a635-c782-4266-a7d4-0a428078b619/image.png" alt="">
그리고 밑에 뜨는 커맨드창에 &#39;ls&#39;를 입력하면 빌드 정보가 뜬다.</p>
<p>ㅠㅠ 힘들엇다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데이터리안 부트캠프] RFM 고객 세분화 분석 포스트를 읽고..]]></title>
            <link>https://velog.io/@l-suyeon-l/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%A6%AC%EC%95%88-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-RFM-%EA%B3%A0%EA%B0%9D-%EC%84%B8%EB%B6%84%ED%99%94-%EB%B6%84%EC%84%9D-%ED%8F%AC%EC%8A%A4%ED%8A%B8%EB%A5%BC-%EC%9D%BD%EA%B3%A0</link>
            <guid>https://velog.io/@l-suyeon-l/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%A6%AC%EC%95%88-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-RFM-%EA%B3%A0%EA%B0%9D-%EC%84%B8%EB%B6%84%ED%99%94-%EB%B6%84%EC%84%9D-%ED%8F%AC%EC%8A%A4%ED%8A%B8%EB%A5%BC-%EC%9D%BD%EA%B3%A0</guid>
            <pubDate>Wed, 10 Sep 2025 10:24:07 GMT</pubDate>
            <description><![CDATA[<p>** [자료] **
<a href="https://datarian.io/blog/what-is-rfm">RFM 고객 세분화 분석이란 무엇일까요</a></p>
<br/>
&nbsp평소 내가 사용하는 어플에서도 광고성 푸시 알람을 자주 받곤한다. 성별, 나이 등의 조건과 상관없이 전송되는 일반 알람도 있지만, 사용자의 정보, 특성, 성향 등을 분석해서 알람을 전송하는 경우도 있다. 나 같은 경우에는 무신사나 에이블리와 같은 패션 어플을 자주 사용하는데, 내가 관심 버튼을 눌러놓은 브랜드의 신상품이라든지 장바구니에 담아놓은 상품의 가격이 하락하는 경우에 푸시 알람이 오기도 한다. 이렇게 일상생활에서 당연하다고 생각했던 것들이 RFM 분석 기법을 통해 사용자를 구분해서 이루어진 전략이었다는 것이 흥미로웠다.
<br/>
<br/>
<br/>
<br/>



<h3 id="rfm-분석이란">RFM 분석이란</h3>
<p>** - Recency : 얼마나 최근에 구매했는가**
** - Frequency : 얼마나 자주 구매했는가**
** - Monetary : 얼마나 많은 금액을 지출했는가**</p>
<p>로 나눠진다. 즉, 사용자가 얼마나 최근에, 얼마나 자주, 얼마나 많은 금액을 지출했는지에 따라 사용자들의 분포를 확인하거나 사용자 그룹 또는 등급을 나누어 분류하는 분석기법이다. 
<br/></p>
<p>&amp;nbsp사용자의 최근 구매일, 총 구매 횟수, 총 구매 금액을 각각의 기준을 세워 recent/past, high/low, high/low의 값으로 변환하고 간단하게 분류한 것에 조금 놀랐다. 복잡한 데이터들을 기준 하나로 이렇게 간단하게 표현할 수 있구나 깨달았다. 물론, 실무에서 다뤄지는 데이터들은 이 예시보다 훨씬 복잡하고 분석이 어려울 것이다. 하지만, 천리길도 한 걸음부터라고 이런 RFM 분석 기법의 기초를 데이터리안에서 하나씩 배워가면 나만의 데이터 분석 방법이 생길 것이라고 믿어 의심치 않는다.
<br/>
<br/></p>
<p>&amp;nbsp지금까지의 데이터리안 부트캠프에서는 MySQL 언어를 배우고 적용하고 코딩테스트를 진행해보는 비교적 간단한 과제들을 했다. 남은 2주 동안은 RFM 고객 세분화 분석, 데이터 연결, EDA, 매출 분석 등 진짜로 실무에서 이루어지는 내용들을 배울 것이다. 드디어 이런 내용들을 배울 수 있다는 게 설렌다.</p>
<p>&amp;nbsp&#39;데이터리안 부트캠프 입문반&#39;을 수강하는 9월 한달 동안의 내 목표는, 원하는 데이터를 직접 찾아보고, 분석하고, 높은 퀄리티의 데이터분석 결과를 도출해내는 것이다. 물론, 나는 전문가가 아니라서 시행착오가 많을 것이라고 생각한다. 하지만, 막히는 부분이나 어떻게 분석해야할 지 모를 때에는 멘토분들께 여쭤가면서 적극적으로 해볼 예정이다. 데이터리안 부트캠프에서는 언제 어디서나, 멘토분들께 편하게 여쭤볼 수 있다는 게 정말 큰 장점인 것 같다. 남은 2주도, 다음 달의 실전반도 열심히 참여해야겠다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Google Colab에서 CUDA C++ 실행하기]]></title>
            <link>https://velog.io/@l-suyeon-l/Google-Colab%EC%97%90%EC%84%9C-CUDA-C-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@l-suyeon-l/Google-Colab%EC%97%90%EC%84%9C-CUDA-C-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 09 Sep 2025 02:23:49 GMT</pubDate>
            <description><![CDATA[<p>&amp;nbsp현재 학교에서 &#39;대규모병렬컴퓨팅&#39;이라는 과목을 수강 중이다.
이 강의에서 실습을 진행하려면 NVIDIA GPU가 필요하다는데 나는 LG Gram을 사용하고 있어 GPU가 Intel이기 때문에 클라우드 컴퓨팅을 해보려고 한다.</p>
<p>&amp;nbsp클라우드 컴퓨팅? 들어만 봤지 한 번도 해본 적이 없어서 감도 안오고 어떻게 해야할 지 모르겠던 와중 에브리타임에서 어떤 분이 Google Colab으로 실습할 것이라고 말씀하신 것을 보고 나도 코랩으로 해보기로 했다. (감사합니다🥹)
<br/>
<br/></p>
<h3 id="1-구글-드라이브에서-google-colab-추가하기">1. 구글 드라이브에서 Google Colab 추가하기</h3>
<p><img src="https://velog.velcdn.com/images/l-suyeon-l/post/0ce9ee6b-d361-46ef-b9e1-10c1ec9213df/image.png" alt="">
구글 드라이브에 들어오면, 좌측 상단에 &#39;+ 신규&#39; 버튼이 있다.
<br/>
<br/></p>
<p><img src="https://velog.velcdn.com/images/l-suyeon-l/post/ebc02078-b06e-4686-94d0-2ad2c8dfb63d/image.png" alt=""></p>
<p>&amp;nbsp신규 버튼을 누르면 가장 아래 &#39;더보기&#39;에 들어가야 하는데, Google Colab을 사용해본 적이 없다면 코랩이 뜨지 않을 것이다. 그러면 &#39;+ 연결할 앱 더보기&#39; 를 눌러서 마켓플레이스에서 Google Colab을 설치해야 한다.</p>
<p>&amp;nbsp설치하면 위 더보기 란에 자동으로 추가된다. 다시 돌아와서 Google Colab을 열어주면 Google Colab 설치는 끝이다.
<br/>
<br/>
<br/></p>
<h3 id="2-gpu-사용-설정하기">2. GPU 사용 설정하기</h3>
<p><img src="https://velog.velcdn.com/images/l-suyeon-l/post/662b7fef-ba77-473b-8863-f40db1d79165/image.png" alt="">
Google Colab에 들어오면 이렇게 보인다.
<br/>
<br/>
먼저, CUDA 실행을 위한 GPU 설정부터 해야하는데,
<img src="https://velog.velcdn.com/images/l-suyeon-l/post/77a932e6-b426-4a58-ac34-fa994d404cdb/image.png" alt="">
상단의 &#39;런타임&#39; - &#39;런타임 유형 변경&#39;을 눌러 들어간다.
<br/><br/></p>
<p><img src="https://velog.velcdn.com/images/l-suyeon-l/post/9a20b04b-541b-49a2-a1be-599948bda09f/image.png" alt="">
우리는 GPU를 사용해야 하기 때문에
<strong>- 런타임 유형 : Python3
- 하드웨어 가속기 : T4 GPU</strong>
로 설정해준다.</p>
<p>&amp;nbsp내가 서치해서 본 글들은 전부 2018~2022년 글이라서 이 부분의 UI가 조금씩 달랐다. &#39;런타임 유형 변경&#39; 이 아닌 &#39;노트 설정&#39;, 하드웨어 가속기도 &#39;T4 GPU&#39;가 아닌 그냥 &#39;GPU&#39;였다. 그래서 조금 헷갈리긴 했는데, 일단 설정해보고 실행해보니 돼서 이 설정이 맞는 듯하다.
<br/>
<br/>
<br/></p>
<h3 id="3-cuda-작업환경-설정하기">3. CUDA 작업환경 설정하기</h3>
<p>&amp;nbspGoogle Colab에는 이미 CUDA가 설치되어 있기 때문에 잘 설치되어 있는지만 확인하면 된다.
<br/></p>
<h4 id="cuda-설치-여부-확인하기">CUDA 설치 여부 확인하기</h4>
<p><code>!nvcc --version</code></p>
<p>위 코드를 넣고 실행하면</p>
<pre><code>nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2024 NVIDIA Corporation
Built on Thu_Jun__6_02:18:23_PDT_2024
Cuda compilation tools, release 12.5, V12.5.82
Build cuda_12.5.r12.5/compiler.34385749_0</code></pre><p>이렇게 결과가 나오면 NVIDA GPU에서 CUDA가 정상적으로 실행된다는 의미이다.
<br/></p>
<h4 id="플러그인-설치하기">플러그인 설치하기</h4>
<p>우리는 CUDA에서 C/C++을 이용할 것이기 때문에 플러그인을 설치해주어야 한다.<br/>
<code>!pip install nvcc4jupyter</code></p>
<pre><code>Collecting nvcc4jupyter
  Downloading nvcc4jupyter-1.2.1-py3-none-any.whl.metadata (5.1 kB)
Downloading nvcc4jupyter-1.2.1-py3-none-any.whl (10 kB)
Installing collected packages: nvcc4jupyter
Successfully installed nvcc4jupyter-1.2.1</code></pre><p>이렇게 nvcc4jupyter을 설치해주면 위와 같이 성공적으로 설치가 완료되었다는 문구가 뜨고, 이제 이 nvcc4jupyter을 사용하기 위해 로드를 해주면 끝이다.
<br/></p>
<h4 id="플러그인-로드하기">플러그인 로드하기</h4>
<p><code>%load_ext nvcc4jupyter</code></p>
<pre><code>Detected platform &quot;Colab&quot;. Running its setup...
Source files will be saved in &quot;/tmp/tmpzftpf343&quot;.</code></pre><p>성공적으로 로드되었다.
<br/>
<br/></p>
<p>&amp;nbsp플러그인 설치-로드 과정에서 시행착오를 겪었는데, 2022년 글을 참고해서 그런지 intall도 github 저장소의 패키지를 설치하고, 플러그인 로드도 &#39;nvcc4jupyter&#39;가 아닌 &#39;nvcc_plugin&#39;이었다. 그래서 <code>%load_ext nvcc_plugin</code>을 하는 과정에서 계속 오류가 뜨고, Google Colab 내부의 AI도 해결하지 못해서 구글링을 해서 다른 방안을 찾아냈고, 찾아낸 것이 이 방법이다.</p>
<p>&amp;nbsp사실 영어를 못하는 건 아닌데 읽기가 너무 귀찮아서 여태까지 프로그래밍을 하면서 최대한 영어 문서를 피해다녔다. 그런데 오늘, 무슨 심정의 변화가 있었는지 영어로된 AI 말을 읽고, 영어로 검색하고, 영어 문서를 읽었는데 생각보다 힘들지 않았다. 앞으로 영문 검색과 영문서 읽기를 습관화 해봐야겠다.
<br/>
<br/>
<br/></p>
<h3 id="4-실행-확인하기">4. 실행 확인하기</h3>
<p>설치가 완료되었다면 마지막으로 CUDA에서 C/C++ 코드가 실행되는지 확인해야한다.</p>
<pre><code>%%cuda
#include &lt;iostream&gt;
    int
    main()
{
    std::cout &lt;&lt; &quot;Hello, World\n&quot;;
    return 0;
}</code></pre><p>위 코드를 실행해보고 &#39;Hello, World&#39;가 잘 뜨는지 확인해보면 된다.</p>
<p><br/><br/>
<strong>[참고문서]</strong></p>
<ul>
<li><a href="https://hichoe95.tistory.com/29#google_vignette">Google Colab 사용하기</a></li>
<li>[Colab에서 CUDA로 C++ 사용하기]
(<a href="https://velog.io/@lamknh/Colab%EC%97%90%EC%84%9C-CUDA-%EB%8F%8C%EB%A6%AC%EA%B8%B0">https://velog.io/@lamknh/Colab%EC%97%90%EC%84%9C-CUDA-%EB%8F%8C%EB%A6%AC%EA%B8%B0</a>)</li>
<li>[Colab에서 C/C++ 플러그인 설치하기]
(<a href="https://www.geeksforgeeks.org/c/how-to-run-cuda-c-c-on-jupyter-notebook-in-google-colaboratory/">https://www.geeksforgeeks.org/c/how-to-run-cuda-c-c-on-jupyter-notebook-in-google-colaboratory/</a>)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[C++ 코딩테스트 문법 정리]]></title>
            <link>https://velog.io/@l-suyeon-l/C-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%AC%B8%EB%B2%95-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@l-suyeon-l/C-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%AC%B8%EB%B2%95-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Thu, 22 May 2025 07:06:56 GMT</pubDate>
            <description><![CDATA[<p><strong>[Do it! 알고리즘 코딩테스트 with C++]</strong> 교재를 따라 공부하는 중입니다.
새롭게 알게 된 라이브러리나 문법이 있으면 실시간으로 정리합니다.</p>
<p><br><br>
<strong>[5/20]</strong></p>
<h4 id="--vector-원소의-합-구하기">- vector 원소의 합 구하기</h4>
<p>라이브러리 : #include &lt;numeric&gt;
함수 : accumulate(InputIt first, InputIt last, T init);</p>
<p>first : 계산 시작 위치
last : 계산 마지막 위치
init : sum의 초기값
<br></p>
<h4 id="예제">예제</h4>
<pre><code>#include &lt;numeric&gt;

sum = accumulate(v.begin(), v.end(), 0);    // 소수점 결과가 필요하다면 sum 파라미터에 double(0)을 넣어도 됨</code></pre><p><br><br></p>
<h4 id="--vector-원소의-최대값--최소값">- vector 원소의 최대값 &amp; 최소값</h4>
<p>라이브러리 : #inlcude &lt;algorithm&gt;
함수
① 최대값 인덱스 구하기
max_element(v.begin(), v.end()) - v.begin();
② 최대값 구하기
*max_element(v.begin(), v.end());
③ 최소값 인덱스 구하기
min_element(v.begin(), v.end()) - v.begin();
④ 최소값 구하기
*min_element(v.begin, v.end());
<br></p>
<h4 id="예제-1">예제</h4>
<pre><code>#include &lt;algorithm&gt;

int max_idx = max_element(v.begin(), v.end()) - v.begin();
int max = *max_element(v.begin(), v.end());

int min_idx = min_element(v.begin(), v.end()) - v.begin;
int min = *min_element(V.begin(), v.end());</code></pre><p><br><br>
<strong>[8/18]</strong></p>
<h4 id="--시간-단축하기">- 시간 단축하기</h4>
<p>① ios::sync_with_stdio(false)
C의 stdio와 C++의 iostream의 동기화를 비활성화함. C++ 독립 버퍼 사용</p>
<p>② cin.tie(NULL), cout.tie(NULL)
하나로 묶인 cin, cout 스트림을 해제함. cin과 cout은 기본적으로 하나로 묶여있는데, cin을 수행하기 전 cout 출력 버퍼를 지움으로써 속도를 향상</p>
<p>③ \n 사용
C++에서는 개행을 위해 보통 endl을 사용하지만, endl보다 \n을 사용하는 편의 속도가 더 빠름</p>
<p><br><br></p>
<h4 id="--동적-배열-생성">- 동적 배열 생성</h4>
<p>① 1차원 동적 배열
② 2차원 동적 배열</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React - Props]]></title>
            <link>https://velog.io/@l-suyeon-l/React-Props</link>
            <guid>https://velog.io/@l-suyeon-l/React-Props</guid>
            <pubDate>Mon, 14 Oct 2024 07:23:42 GMT</pubDate>
            <description><![CDATA[<h3 id="props">props</h3>
<blockquote>
<p>properties. 컴포넌트의 속성을 설정할 때 사용하는 요소</p>
</blockquote>
<br>

<h4 id="props-렌더링">props 렌더링</h4>
<br>

<p><span style='background-color: #ffdce0;
             font-size: 15px;
             display: block;' >&nbsp;&nbsp;&nbsp;&nbsp;MyComponent.js</span></p>
<pre><code class="language-javascript">const MyComponent = props =&gt; {
    return &lt;div&gt;안녕하세요, 제 이름은 {props.name}입니다.&lt;/div&gt;;
};

export default MyComponent;</code></pre>
<p>&nbsp;MyComponent 컴포넌트에서 name이라는 props를 렌더링하도록 설정했다. </p>
<br>

<h4 id="props-값-지정하기">props 값 지정하기</h4>
<br>

<p><span style='background-color: #ffdce0;
             font-size: 15px;
             display: block;' >&nbsp;&nbsp;&nbsp;&nbsp;App.js</span></p>
<pre><code class="language-javascript">import MyComponent from &#39;./MyComponent&#39;;

const App = () =&gt; {
    return &lt;MyComponent name=&quot;react&quot; /&gt;;
};

export default App;


// 출력 결과 : 안녕하세요, 제 이름은 react입니다.</code></pre>
<br>
&nbsp;외부 컴포넌트에서 MyComponent의 props을 설정했다. props의 값은 컴포넌트 함수의 파라미터로 받아 와서 사용할 수 있고, props를 렌더링할 때에는 JSX 내부에서 { } 기호로 감싸면 된다.

<br>

<h4 id="props-기본값-설정--defaultprops">props 기본값 설정 : defaultProps</h4>
<br>

<p><span style='background-color: #ffdce0;
             font-size: 15px;
             display: block;' >&nbsp;&nbsp;&nbsp;&nbsp;MyComponent.js</span></p>
<pre><code class="language-javascript">const MyComponent = props =&gt; {
    return &lt;div&gt;안녕하세요, 제 이름은 {props.name}입니다.&lt;/div&gt;;
};


MyComponent.defaultProps = {
    name : &#39;최수연&#39;
};

export default MyComponent;


// 출력 결과 : 안녕하세요, 제 이름은 최수연입니다.</code></pre>
<p><br><br></p>
<h4 id="children">children</h4>
<p>컴포넌트 태그 사이의 내용을 보여주는 props이다
<br></p>
<p><span style='background-color: #ffdce0;
             font-size: 15px;
             display: block;' >&nbsp;&nbsp;&nbsp;&nbsp;App.js</span></p>
<pre><code class="language-javascript">import MyComponent from &#39;./MyComponent&#39;;

const App = () =&gt; {
    return &lt;MyComponent&gt;리액트&lt;/MyComponent&gt;;
};

export default App;</code></pre>
<p>&nbsp;위 코드에서 MyComponent 태그 사이에 작성한 문자열을 MyComponent 파일 내부에서 보여주려면 <strong>props.children</strong>을 사용한다.
<br></p>
<p><span style='background-color: #ffdce0;
             font-size: 15px;
             display: block;' >&nbsp;&nbsp;&nbsp;&nbsp;MyComponent.js</span></p>
<pre><code class="language-javascript">const MyComponent = props =&gt; {
    return (
        &lt;div&gt;
            안녕하세요, 제 이름은 {props.name}입니다. &lt;br /&gt;
            children 값은 {props.childern}
            입니다.
        &lt;/div&gt;
    );
};

MyComponent.defaultProps = {
    name : &#39;기본 이름&#39;
};

export default MyComponent;

// 출력 결과 : 안녕하세요, 제 이름은 최수연입니다.
//              children 값은 리액트입니다.</code></pre>
<p><br><br></p>
<h4 id="비구조화-할당-문법--내부-값-바로-추출하기">비구조화 할당 문법 : 내부 값 바로 추출하기</h4>
<p>&nbsp;위의 MyComponent에서는 props의 값을 조회할 때마다 <strong>&#39;props.&#39;</strong>라는 키워드를 붙여주고 있다. 이러한 작업을 생략하기 위해 비구조화 할당 문법을 사용하여 내부 값을 바로 추출하는 방법이 있다.
<br></p>
<p><span style='background-color: #ffdce0;
             font-size: 15px;
             display: block;' >&nbsp;&nbsp;&nbsp;&nbsp;MyComponent.js</span></p>
<pre><code class="language-javascript">const MyComponent = props =&gt; {
    const { name, children } = props;    // 추가됨
    return (
        &lt;div&gt;
            안녕하세요, 제 이름은 {name}입니다. &lt;br /&gt;
            children 값은 {childern}
            입니다.
        &lt;/div&gt;
    );
};

MyComponent.defaultProps = {
    name : &#39;기본 이름&#39;
};

export default MyComponent;

// 출력 결과 : 안녕하세요, 제 이름은 최수연입니다.
//              children 값은 리액트입니다.</code></pre>
<p>&nbsp;MyComponent.js 파일을 다음과 같이 수정하면 name 값과 children 값을 간결하게 사용할 수 있다. 이와 같이 객체에서 값을 추출하는 문법을 <strong>비구조화 할당(destructuring assignment)</strong>이라고 부른다. 구조 분해 문법이라고도 불리며, 함수의 파라미터 부분에서도 사용할 수 있다.
<br><br></p>
<p><span style='background-color: #ffdce0;
             font-size: 15px;
             display: block;' >&nbsp;&nbsp;&nbsp;&nbsp;MyComponent.js</span></p>
<pre><code class="language-javascript">const MyComponent = ({ name, children }) =&gt; {
    return (
        &lt;div&gt;
            안녕하세요, 제 이름은 {name}입니다. &lt;br /&gt;
            children 값은 {childern}
            입니다.
        &lt;/div&gt;
    );
};

MyComponent.defaultProps = {
    name : &#39;기본 이름&#39;
};

export default MyComponent;

// 출력 결과 : 안녕하세요, 제 이름은 최수연입니다.
//              children 값은 리액트입니다.</code></pre>
<p>&nbsp;객체인 함수 파라미터를 비구조화해서 사용하는 것이다. 이렇게 사용하면 훨씬 편하다. 앞으로도 함수 컴포넌트에서 props를 사용할 때 파라미터 부분에서 비구조화 할당 문법을 사용하도록 한다.</p>
<p><br><br></p>
<h4 id="proptypes를-통한-props-검증">propTypes를 통한 props 검증</h4>
<p>&nbsp;컴포넌트의 필수 props를 지정하거나 props의 타입(type)을 지정할 때는 propTypes를 사용한다. propTypes를 사용하려면 코드 상단에 import 구문을 사용하여 불러와야 한다.
<br></p>
<p><span style='background-color: #ffdce0;
             font-size: 15px;
             display: block;' >&nbsp;&nbsp;&nbsp;&nbsp;MyComponent.js</span></p>
<pre><code class="language-javascript">import PropTypes from &#39;prop-types&#39;;        // propTypes 불러오기

const MyComponent = ({ name, children }) =&gt; {
    return(...);
};

MyComponent.defaultProps = {
    name: &#39;최수연&#39;
};

MyComponent.propTypes = {
    name: propTypes.string
};

export default MyComponent;</code></pre>
<p>&nbsp;위 코드처럼 propType을 설정해 주면 <strong>name 값은 무조건 문자열(string)형태로 전달</strong>해야 된다는 것을 의미한다. App 컴포넌트에서 name 값을 문자열이 아닌 값으로 전달하고, 개발자 도구의 Console 탭을 열어보아라.
<br></p>
<p><span style='background-color: #ffdce0;
             font-size: 15px;
             display: block;' >&nbsp;&nbsp;&nbsp;&nbsp;App.js</span></p>
<pre><code class="language-javascript">import MyComponent from &#39;./MyComponent&#39;;

const App = () =&gt; {
      return &lt;MyComponent name={3}&gt;리액트&lt;/MyComponent&gt;;
};

export default App;

// 출력 결과 : 안녕하세요, 제 이름은 3입니다.</code></pre>
<p><br>&nbsp;MyComponent 컴포넌트에서 name의 propTypes를 string으로 설정하고 App 컴포넌트에서 name을 숫자형으로 설정했을 때 출력은 정상적으로 실행되지만, Console에서는 아래와 같은 오류가 발생한다.
<img src="https://velog.velcdn.com/images/l-suyeon-l/post/90b493c2-07c7-4e33-9e72-38105d6e77e2/image.png" alt="">
&nbsp;위 경고 메세지는 propTypes가 잘못되었다는 것을 알려준다. 오류를 수정하기 위해 App 컴포넌트의 return 부분을 수정해줬다.</p>
<pre><code class="language-javascript">const App = () =&gt; {
  return &lt;MyComponent name=&quot;React&quot;&gt;리액트&lt;/MyComponent&gt;;
};</code></pre>
<p><br><br></p>
<h3 id="isrequired를-통한-필수-proptypes-설정">isRequired를 통한 필수 propTypes 설정</h3>
<p>&nbsp;propTypes를 지정하지 않았을 때 경고 메세지를 띄우 주는 작업을 해 보자. 
<br><br></p>
<p><span style='background-color: #ffdce0;
             font-size: 15px;
             display: block;' >&nbsp;&nbsp;&nbsp;&nbsp;MyComponent.js</span></p>
<pre><code class="language-javascript">import PropTypes from &#39;prop-types&#39;;

const MyComponent = ({ name, children, favoriteNumber }) =&gt; {
    return (
        &lt;div&gt;
            안녕하세요, 제 이름은 {name}입니다. &lt;br /&gt;
            children 값은 {childern}
            입니다. &lt;br /&gt;
            제가 좋아하는 숫자는 {favoriteNumber}입니다.
        &lt;/div&gt;
    );
};

MyComponent.defaultProps = {
    name: &#39;기본 이름&#39;
};

MyComponent.propTypes = {
  name: PropTypes.string,
  favoriteNumber: PropTypes.number.isRequired
};

export default MyComponent;</code></pre>
<br>

<p><span style='background-color: #ffdce0;
             font-size: 15px;
             display: block;' >&nbsp;&nbsp;&nbsp;&nbsp;App.js</span></p>
<pre><code class="language-javascript">import MyComponent from &#39;./MyComponent&#39;;

const App = () =&gt; {
      return &lt;MyComponent name=&quot;React&quot;&gt;리액트&lt;/MyComponent&gt;;
};

export default App;</code></pre>
<p>&nbsp;MyComponent 컴포넌트에 객체 favoriteNumber의 propTypes를 숫자형으로 설정하고 isRequired를 붙여주었다. 코드를 저장한 후 개발자 도구의 Console을 확인해보면 아래와 같은 경고가 나타난다.
<img src="https://velog.velcdn.com/images/l-suyeon-l/post/ad8292b3-3792-4c68-ac34-cfb89ab160b1/image.png" alt="">
&nbsp;오류를 수정하기 위해 App 컴포넌트의 return 부분을 수정해줬다.</p>
<pre><code class="language-javascript">const App = () =&gt; {
  return (
    &lt;MyComponent name=&quot;React&quot; favoriteNumber={1}&gt;리액트&lt;/MyComponent&gt;
  );
};</code></pre>
<p><br><br>
&nbsp;이 글에서는 string과 number PropTypes를 알아봤다. 하지만, PropTypes는 이 외에도 여러가지 종류를 설정할 수 있다.
<br></p>
<ul>
<li>array : 배열</li>
<li>arrayOf(다른 PropType) : 특정 PropType로 이루어진 배열</li>
<li>bool : true/false 값</li>
<li>func : 함수</li>
<li>number : 숫자</li>
<li>object : 객체</li>
<li>string : 문자열</li>
<li>symbol : ES6의 Symbol</li>
<li>node : 렌더링할 수 있는 모든 것(숫자, 문자열, JSX코드, children 등)</li>
<li>instanceOf(클래스) : 특정 클래스의 인스턴스</li>
<li>oneOf([&#39;dog&#39;, &#39;cat&#39;]) : 주어진 배열 요소 중 값 하나</li>
<li>oneOfType([React.PropTypes.string, PropTypes.number]) : 주어진 배열 안의 종류 중 하나</li>
<li>objectOf(React.PropTypes.number) : 객체의 모든 키 값이 인자로 주어진 PropType인 객체</li>
<li>shape({ name: PropTypes.string, num: PropTyes.number }) : 주어진 스키마를 가진 객체</li>
<li>any : 아무 종류</li>
</ul>
<p><br>&nbsp;등 다양한 종류의 PropTypes가 있다. 더 자세한 정보는 <a href="https://github.com/facebook/prop-types">https://github.com/facebook/prop-types</a> 에서 확인할 수 있다.</p>
<p><br><br></p>
<h3 id="클래스형-컴포넌트의-props">클래스형 컴포넌트의 props</h3>
<p>&nbsp;클래스형 컴포넌트에서도 props를 사용할 수 있다. 함수형 컴포넌트와의 차이점은 코드를 확인한 후 알아보자.
<br><br></p>
<p><span style='background-color: #ffdce0;
             font-size: 15px;
             display: block;' >&nbsp;&nbsp;&nbsp;&nbsp;MyComponent.js</span></p>
<pre><code class="language-javascript">import React, { Component } from &#39;react&#39;;
import PropTypes from &#39;prop-types&#39;;

class MyComponent extends Component {
  static defaultProps = {
    date: &#39;기본 이름&#39;
  };

  static propTypes = {
    data: PropTypes.string,
    favoriteNumber: PropTypes.number.isRequired
  };

  render() {
    const { name, children, favoriteNumber } = this.props; // 비구조화 할당
      return (
          &lt;div&gt;
              안녕하세요, 제 이름은 {name}입니다. &lt;br /&gt;
              children 값은 {childern}
              입니다. &lt;br /&gt;
              제가 좋아하는 숫자는 {favoriteNumber}입니다.
          &lt;/div&gt;
      );
  }
};

// 함수 외부에 선언 가능
/*
MyComponent.defaultProps = {
    name: &#39;기본 이름&#39;
};

MyComponent.propTypes = {
  name: PropTypes.string,
  favoriteNumber: PropTypes.number.isRequired
};
*/

export default MyComponent;</code></pre>
<p><br><br></p>
<p><strong>함수형-클래스형 컴포넌트에서의 props 사용 차이점</strong></p>
<ul>
<li>render 함수에서 비구조화 할당과 return을 실행한다</li>
<li>defaultProps와 propTypes는 class 내부에서도 선언 가능하다</li>
</ul>
<br>

<blockquote>
<p><strong>defaultProps와 propTypes는 꼭 사용해야 하는가?</strong>
&nbsp;이 두 가지 설정은 컴포넌트의 필수 사항이 아니므로 꼭 사용할 필요는 없다. 하지만 React를 통해 큰 규모의 프로젝트를 진행한다면, 특히 다른 개발자들과 협업한다면 해당 컴포넌트에서 어떤 props가 필요한지 쉽게 알 수 있어 개발 능률이 좋아질 것이다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[React - 컴포넌트]]></title>
            <link>https://velog.io/@l-suyeon-l/React-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8</link>
            <guid>https://velog.io/@l-suyeon-l/React-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8</guid>
            <pubDate>Sun, 13 Oct 2024 13:05:43 GMT</pubDate>
            <description><![CDATA[<p><strong>&nbsp;리액트는 Component 기반의 구조이다. 모든 페이지가 Component로 구성되어 있고 하나의 Component는 또 다른 여러 개의 Component의 조합으로 구성될 수 있다.</strong></p>
<br>

<h3 id="컴포넌트">컴포넌트</h3>
<h4 id="컴포넌트란">컴포넌트란?</h4>
<blockquote>
<p>사용자 인터페이스 일부를 표시하는 재사용 가능한 코드의 조각</p>
</blockquote>
<p>&nbsp;함수가 입력을 받아 출력을 리턴하는 것처럼 Component도 입력을 받아 정해진 출력을 리턴한다. Component의 입력은 props, 출력은 Element가 된다. 따라서 Component를 마크업을 반환하는 하나의 자바스크립트 함수라고 생각할 수 있다.</p>
<p>&nbsp;컴포넌트는 고유한 로직과 모양을 가진 하나의 작은 UI 덩어리라고 표현할 수 있다. 다시 말해, 페이지를 구성하는 작은 단위이다. 컴포넌트를 통해 UI를 재사용 가능한 개별적인 조각으로 나누고, 각 조각을 상황에 따라 활용할 수 있다. 컴포넌트는 어플리케이션의 UI 엘리먼트를 렌더링, 관리, 업데이트할 때 사용한다.</p>
<br>

<h4 id="컴포넌트의-장점">컴포넌트의 장점</h4>
<ol>
<li>코드 양을 줄일 수 있다.</li>
<li>개발 시간을 줄일 수 있다.</li>
<li>유지 보수 비용이 줄어든다</li>
</ol>
<p><br><br><br></p>
<h3 id="함수형-컴포넌트">함수형 컴포넌트</h3>
<p>&nbsp;이전의 &#39;React - 1&#39; 포스팅에서 사용했던 App 컴포넌트가 <strong>함수형 컴포넌트</strong>이다.</p>
<h4 id="함수형-컴포넌트의-구조">함수형 컴포넌트의 구조</h4>
<p><span style='background-color: #ffdce0;
             font-size: 15px;
             display: block;' >&nbsp;&nbsp;&nbsp;&nbsp;App.js</span></p>
<pre><code class="language-javascript">import &#39;./App.css&#39;;

function App() {
    const name = &#39;react&#39;;
    return &lt;div className=&quot;react&quot;&gt;{name}&lt;/div&gt;;
}

export default App;        // export default : 파일의 기본 컴포넌트 지정</code></pre>
<br>

<h4 id="함수형-컴포넌트의-장점">함수형 컴포넌트의 장점</h4>
<ul>
<li>클래스형 컴포넌트보다 선언하기 쉽다</li>
<li>클래스형 컴포넌트보다 메모리 자원을 덜 사용한다</li>
<li>프로젝트를 완성하여 빌드한 후 배포할 때 파일 크기가 작다</li>
</ul>
<br>

<h4 id="함수형-컴포넌트의-단점">함수형 컴포넌트의 단점</h4>
<ul>
<li>state와 라이프사이클 API 사용이 불가능하다
=&gt; Hooks 기능 도입으로 비슷한 작업이 가능하게 되었다</li>
</ul>
<p><br><br><br></p>
<h3 id="클래스형-컴포넌트">클래스형 컴포넌트</h3>
<h4 id="클래스형-컴포넌트의-구조">클래스형 컴포넌트의 구조</h4>
<br>

<p><span style='background-color: #ffdce0;
             font-size: 15px;
             display: block;' >&nbsp;&nbsp;&nbsp;&nbsp;App.js</span></p>
<pre><code class="language-javascript">import React, { Component } from &#39;react&#39;;

class App extends Component {
    render() {
        const name = &#39;react&#39;;
        return &lt;div className=&#39;react&#39;&gt;{name}&lt;/div&gt;;
    }
}

export default App;</code></pre>
<br>

<h4 id="클래스형-컴포넌트의-장점">클래스형 컴포넌트의 장점</h4>
<ul>
<li>state 기능을 사용할 수 있다</li>
<li>라이프사이클 기능을 사용할 수 있다</li>
<li>임의 메서드를 정의할 수 있다</li>
</ul>
<br>

<h4 id="클래스형-컴포넌트의-특징">클래스형 컴포넌트의 특징</h4>
<ul>
<li>render 함수가 꼭 있어야 한다</li>
<li>JSX를 반환해야 한다
<br><br><br><br><br><h3 id="컴포넌트-렌더링">컴포넌트 렌더링</h3>
뭔소리야..?</li>
</ul>
<br>

<p><strong>※ 리액트 공식 매뉴얼에서는 함수 컴포넌트와 Hooks 사용을 권장하고 있다.</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React - 모듈]]></title>
            <link>https://velog.io/@l-suyeon-l/React-%EB%AA%A8%EB%93%88</link>
            <guid>https://velog.io/@l-suyeon-l/React-%EB%AA%A8%EB%93%88</guid>
            <pubDate>Fri, 13 Sep 2024 14:27:10 GMT</pubDate>
            <description><![CDATA[<h3 id="모듈-내보내기export">모듈 내보내기(export)</h3>
<br>

<p><strong>[MyComponent.js]</strong></p>
<pre><code class="language-javascript">export default MyComponent;</code></pre>
<p>&nbsp;다른 파일(App.js)에서 이 파일(MyComponent.js)를 import할 때, 위에서 선언한 MyComponent 컴포넌트를 불러오도록 설정한다</p>
<p><br><br></p>
<p><strong>[App.js]</strong></p>
<pre><code class="language-javascript">import MyComponent from &#39;./MyComponent&#39;;

const App = () =&gt; {
    return &lt;MyComponent /&gt;;
};

export default App;</code></pre>
<p>&nbsp;import 구문을 사용하여 MyComponent 컴포넌트를 불러온다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript - 화살표 함수]]></title>
            <link>https://velog.io/@l-suyeon-l/JavaScript-%ED%99%94%EC%82%B4%ED%91%9C-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@l-suyeon-l/JavaScript-%ED%99%94%EC%82%B4%ED%91%9C-%ED%95%A8%EC%88%98</guid>
            <pubDate>Fri, 13 Sep 2024 14:18:14 GMT</pubDate>
            <description><![CDATA[<h3 id="화살표-함수-arrow-function">화살표 함수 (arrow function)</h3>
<br>

<p><strong>구현 방법</strong></p>
<p><strong>1. 변수를 선언하고, 그 위치에 함수를 선언한다.</strong></p>
<pre><code class="language-jsx">let add = function(num1, num2) {
    return num1 + num2;
}</code></pre>
<p><strong>2. 함수명 ‘function’을 없애고, 괄호 우측에 화살표를 표시한다.</strong></p>
<pre><code class="language-jsx">let add = (num1, num2) =&gt; {
    return num1 + num2;
}</code></pre>
<br>

<h4 id="주의사항">주의사항</h4>
<ul>
<li>함수 코드에 return문만 있을 때에는 중괄호에서 소괄호로 바꿀 수 있다.</li>
</ul>
<pre><code class="language-jsx">let add = (num1, num2) =&gt; (
    num1 + num2;
)</code></pre>
<ul>
<li>함수 코드에 여러 줄의 코드가 있을 경우 소괄호로 바꿀 수 없다.</li>
</ul>
<pre><code class="language-jsx">let add = function(num1, num2) {
    const result = num1 + num2;
    return result;
}</code></pre>
<ul>
<li><p>return이 한 줄이라면 괄호는 생략 가능하다</p>
<pre><code class="language-jsx">let add = (num1, num2) =&gt; num1 + num2;</code></pre>
</li>
<li><p>매개변수가 하나라면 괄호는 생략 가능하다</p>
</li>
</ul>
<pre><code class="language-jsx">let sayHello = name =&gt; Hello, ${name};</code></pre>
<ul>
<li>매개변수가 없는 함수라면 괄호는 생략 불가능하다</li>
</ul>
<pre><code>let showError = () =&gt; {
    alert(&#39;error!&#39;);
}</code></pre><p><br><br></p>
<h4 id="화살표-함수의-this">화살표 함수의 this</h4>
<p>: 화살표 함수에는 &#39;this&#39;가 없기 때문에 상위 스코프의 this를 참조한다</p>
<pre><code>function BlackDog() {
    this.name = &#39;흰둥이&#39;;
    return {
        name : &#39;검둥이&#39;,
        bark : function() {
            console.log(this.name + &#39;: 멍멍!&#39;);
        }
    }
}

const blackDog = new BlackDog();
blackDog.bark();    // 검둥이 : 멍멍!</code></pre><p>&nbsp;메소드로 function()을 사용했을 때에는 name으로 &#39;검둥이&#39;가 나타난다. 일반 함수는 자신이 종속된 객체를 this로 가리키기 때문이다.</p>
<p><br><br><br></p>
<pre><code>function WhiteDog() {
    this.name = &#39;흰둥이&#39;;
    return {
        name : &#39;검둥이&#39;,
        bark : () =&gt; {
            console.log(this.name + &#39;: 멍멍!&#39;);
        }
    }
}

const whiteDog = new WhiteDog();
whiteDog.bark();    // 흰둥이 : 멍멍!</code></pre><p>&nbsp;메소드로 () =&gt;를 사용했을 때에는 name으로 &#39;흰둥이&#39;가 나타난다. 화살표 함수는 자신이 종속된 인스턴스를 가리키기 때문이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React - 기초]]></title>
            <link>https://velog.io/@l-suyeon-l/React-1</link>
            <guid>https://velog.io/@l-suyeon-l/React-1</guid>
            <pubDate>Mon, 09 Sep 2024 13:10:03 GMT</pubDate>
            <description><![CDATA[<h3 id="appjs-코드-분석">App.js 코드 분석</h3>
<pre><code class="language-javascript">import logo from &#39;./logo.svg&#39;;    // import : 특정 파일을 불러옴  &lt;-  자바스크립트 파일에서는 import를 사용해서 다른 파일들을 불러와 사용가능
import &#39;./App.css&#39;;               // 모듈을 불러와서 사용하는 것은 브라우저에는 X. Node.js에서 지원하는 기능

function App() {          // &#39;App&#39;이라는 함수 컴포넌트 생성(function)
  return (                // 반환값은 HTML이 아님. JSX이다.
    &lt;div className=&quot;App&quot;&gt;
      &lt;header className=&quot;App-header&quot;&gt;
        &lt;img src={logo} className=&quot;App-logo&quot; alt=&quot;logo&quot; /&gt;
        &lt;p&gt;
          Edit &lt;code&gt;src/App.js&lt;/code&gt; and save to reload.
        &lt;/p&gt;
        &lt;a
          className=&quot;App-link&quot;
          href=&quot;https://reactjs.org&quot;
          target=&quot;_blank&quot;
          rel=&quot;noopener noreferrer&quot;
        &gt;
          Learn React
        &lt;/a&gt;
      &lt;/header&gt;
    &lt;/div&gt;
  );
}

export default App;
</code></pre>
<p><br><br></p>
<h3 id="jsx의-장점">JSX의 장점</h3>
<ol>
<li>보기 쉽고 익숙하다</li>
<li>더욱 높은 활용도
=&gt; 한 파일에서 생성된 컴포넌트를 다른 파일에서 import하여 HTML 태그 쓰듯이 작성할 수 있다</li>
</ol>
<br>

<h3 id="jsx-문법">JSX 문법</h3>
<h4 id="1-감싸인-요소">1. 감싸인 요소</h4>
<p>컴포넌트에 여러 요소가 있다면 반드시 부모 요소 하나로 감싸야 함.</p>
<pre><code class="language-javascript">function App() {
    return (
        &lt;h1&gt;안녕하세요&lt;/h1&gt;
        &lt;h2&gt;잘 작동하나?&lt;/h2&gt;
    );
}

export default App;</code></pre>
<br>
<div>
  <strong>=> 오류발생</strong><br>
  <img align=left src="https://velog.velcdn.com/images/l-suyeon-l/post/52037a66-889f-468c-8e54-b0f612c564e9/image.png">
</div>
<br><br><br><br><br>


<h4 id="해결법">해결법</h4>
<p>: 여러 태그들을 한 개의 div 태그로 감싼다</p>
<pre><code class="language-javascript">function App() {
    return (
        &lt;div&gt;
            &lt;h1&gt;안녕하세요&lt;/h1&gt;
            &lt;h2&gt;잘 작동하나?&lt;/h2&gt;
        &lt;/div&gt;
    );
}

export default App;</code></pre>
<br>

<p><strong>왜 하나의 요소로 감싸야할까?</strong>
: Virtual DOM에서 컴포넌트의 변화를 감지할 때 <em>효율적으로 비교할 수 있도록 하기 위해</em>&nbsp; 컴포넌트 내부는 <strong>하나의 DOM 트리 구조</strong>로 이루어져야한다는 규칙이 있기 때문이다.</p>
<br>
div 요소를 사용하고 싶지 않다면 'Fragment'기능도 사용 가능하다.

<pre><code class="language-javascript">import {Fragment} from &#39;react&#39;;

function App() {
    return (
        &lt;Fragment&gt;
            &lt;h1&gt;안녕하세요&lt;/h1&gt;
            &lt;h2&gt;잘 작동하나?&lt;/h2&gt;
        &lt;/Fragment&gt;
    );
}

export default App;</code></pre>
<br>
이렇게도 표현할 수 있다

<pre><code class="language-javascript">import {Fragment} from &#39;react&#39;;

function App() {
    return (
        &lt;&gt;
            &lt;h1&gt;안녕하세요&lt;/h1&gt;
            &lt;h2&gt;잘 작동하나?&lt;/h2&gt;
        &lt;/&gt;
    );
}

export default App;</code></pre>
<p><br><br></p>
<h4 id="2-자바스크립트-표현">2. 자바스크립트 표현</h4>
<p>&nbsp;JSX에서는 DOM 요소를 렌더링하는 기능뿐만 아니라 자바스크립트 표현식도 사용할 수 있다.</p>
<pre><code class="language-javascript">function App() {
  const name = &#39;react&#39;;
  return (                        
    &lt;div&gt;
      &lt;h1&gt;안녕 {name}!&lt;/h1&gt;
      &lt;h2&gt;잘 작동하나?&lt;/h2&gt;
    &lt;/div&gt;
  );
}

export default App;</code></pre>
<p><br><br></p>
<h4 id="3-if문-대신-조건부-연산자">3. If문 대신 조건부 연산자</h4>
<p>&nbsp;JSX 내부의 자바스크립트 표현식에서는 if문을 사용할 수 없다. 조건에 따라 다른 내용을 렌더링해야 할 때는 <strong>(1) JSX 밖에서 if문을 사용하여 사전에 값을 설정</strong>하거나, <strong>(2) {} 안에 조건부 연산자를 사용</strong>하면 된다.</p>
<pre><code class="language-javascript">function App() {
  const name = &#39;react&#39;;
  return (                        
    &lt;div&gt;
      {name === &#39;react&#39; ? (        // 삼항 연산자
        &lt;h1&gt;react입니다.&lt;/h1&gt;
      ) : (
        &lt;h2&gt;react가 아닙니다.&lt;/h2&gt;
      )}
    &lt;/div&gt;
  );
}

export default App;</code></pre>
<p><br><br></p>
<h4 id="4-and-연산자를-사용한-조건부-렌더링">4. AND 연산자(&amp;&amp;)를 사용한 조건부 렌더링</h4>
<p>&nbsp;특정 조건을 만족하지 않을 때 아무것도 렌더링하지 않아야 하는 상황에서, <strong>조건부 연산자</strong>를 통해 구현할 수 있지만</p>
<pre><code class="language-javascript">function App() {
  const name = &#39;react&#39;;
  return (                        
    &lt;div&gt;
      {name === &#39;react&#39; ? &lt;h1&gt;react입니다.&lt;/h1&gt; : null}
    &lt;/div&gt;
  );
}

export default App;</code></pre>
<br>

<p><strong>AND 연산자(&amp;&amp;)</strong>를 통해서 더 짧은 코드로 똑같은 작업을 할 수 있다.</p>
<pre><code class="language-javascript">function App() {
  const name = &#39;react&#39;;
  return (                        
    &lt;div&gt;
      {name === &#39;react&#39; &amp;&amp; &lt;h1&gt;react입니다.&lt;/h1&gt;}
    &lt;/div&gt;
  );
}

export default App;</code></pre>
<p><br><br></p>
<h4 id="5-undefined를-렌더링하지-않기">5. undefined를 렌더링하지 않기</h4>
<p>&nbsp;리액트 컴포넌트에서는 함수에서 undefined만 반환하여 렌더링하면 안된다. 그렇게 되면, 다음과 같은 오류를 발생시킨다.</p>
<pre><code class="language-javascript">import &#39;./App.css&#39;

function App() {
  const name = undefined;
  return name;
}

export default App;



App(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.</code></pre>
<br>

<h4 id="해결법-1">해결법</h4>
<p>&nbsp;어떤 값이 undefined일 수 있다면, <strong>Or 연산자(||)</strong>를 사용하면 <em>해당 값이 undefined일 때 대신 사용할 값을 지정할 수 있어</em>&nbsp; 오류를 방지할 수 있다.</p>
<pre><code class="language-javascript">import &#39;./App.css&#39;

function App() {
  const name = undefined;
  return name || &#39;값이 undefined입니다.&#39;;
}

export default App;</code></pre>
<br>
→ JSX 내부에서 undefined를 렌더링하는 것은 괜찮다.

<pre><code class="language-javascript">import &#39;./App.css&#39;

function App() {
  const name = undefined;
  return &lt;div&gt;{name}&lt;/div&gt;;
}

export default App;</code></pre>
<br>
→ name 값이 undefined일 때 보여주고 싶은 문구가 있다면 다음과 같이 코드를 작성하면 된다.

<pre><code class="language-javascript">import &#39;./App.css&#39;

function App() {
  const name = undefined;
  return &lt;div&gt;{name || &#39;보여주고 싶은 문구&#39;}&lt;/div&gt;;
}

export default App;</code></pre>
<p><br><br></p>
<h4 id="6-인라인-스타일링">6. 인라인 스타일링</h4>
<p>&nbsp;인라인 스타일링이란, html 태그에 직접 style을 적용하는 방식이다. 리액트에서 DOM 요소에 style을 적용할 때에는 문자열 형태가 아닌, <strong>객체 형태</strong>로 적용해야 한다.
<br></p>
<p><strong>(1) style 객체 미리 선언 후 적용</strong></p>
<pre><code class="language-javascript">import &#39;./App.css&#39;

function App() {
  const name = &#39;react&#39;;
  const style = {
    backgroundColor: &#39;black&#39;,    // 카멜 표기법(camelCase)
    color: &#39;aqua&#39;,
    fontSize: &#39;48px&#39;,            // font-size =&gt; fontSize
    fontWeight: &#39;bold&#39;,            // font-weight =&gt; fontWeight
    padding: 16                    // 단위 생략시 px
  };
  return &lt;div style={style}&gt;{name}&lt;/div&gt;;
}

export default App;</code></pre>
<br>

<p>** (2) style 바로 선언 **</p>
<pre><code>import &#39;./App.css&#39;

function App() {
  const name = &#39;react&#39;;
  return &lt;div 
            style={{
              backgroundColor: &#39;black&#39;,
              color: &#39;aqua&#39;,
              fontSize: &#39;48px&#39;,
              fontWeight: &#39;bold&#39;,
              padding: 16
            }}
          &gt;
            {name}
          &lt;/div&gt;;
}

export default App;</code></pre><p><br><br></p>
<h4 id="7-class-→-classname">7. class → className</h4>
<p>&nbsp;일반 HTML에서 CSS 클래스를 사용할 때에는 <code>&lt;div class=&quot;react&quot;&gt;&lt;/div&gt;</code>와 같이 class 속성을 설정한다. JSX에서는 class가 아닌 <strong>className</strong>으로 설정해주어야 한다.</p>
<pre><code class="language-javascript">[ App.css ]

.react {
  background: aqua;
  color: black;
  font-size: 48px;
  font-weight: bold;
  padding: 16px;
}</code></pre>
<pre><code class="language-javascript">[ App.js ]

import &#39;./App.css&#39;

function App() {
  const name = &#39;react&#39;;
  return &lt;div className=&quot;react&quot;&gt;{name}&lt;/div&gt;;
}

export default App;</code></pre>
<br>
&nbsp;JSX 작성 시 CSS 클래스를 설정하는 과정에서 className이 아닌 class로 설정해도 스타일이 적용된다. 하지만 그렇게 되면 브라우저 개발자 도구의 Console 탭에 다음과 같은 경고가 나타난다.

<pre><code class="language-javascript">Warning: Invalid DOM property `class`. Did you mean `className
    in div (at App.js:6)
    in App (at src/index.js:7)</code></pre>
<p><br><br></p>
<h4 id="8-꼭-닫아야-하는-태그">8. 꼭 닫아야 하는 태그</h4>
<p>&nbsp;HTML에서는 <code>&lt;input&gt;</code>, <code>&lt;br&gt;</code>과 같이 태그를 닫지 않아도 되는 오픈 태그가 존재한다. 하지만, JSX에서는 태그를 닫지 않으면 오류가 발생한다. 따라서 오픈 태그도 닫아주어야 한다.</p>
<pre><code class="language-javascript">import &#39;./App.css&#39;

function App() {
  const name = &#39;react&#39;;
  return (
    &lt;&gt;
      &lt;div className=&quot;react&quot;&gt;{name}&lt;/div&gt;
      &lt;input&gt;&lt;/input&gt;
    &lt;/&gt;
  )
}

export default App;</code></pre>
<br>

<p>&nbsp;태그 사이에 별도의 내용이 들어가지 않는 경우에는 다음과 같이 작성할 수 있다. 우리는 이러한 태그를 <strong>self-closing 태그</strong>라고 한다. <del>태그를 선언하면서 동시에 닫을 수 있다.</del></p>
<pre><code class="language-javascript">import &#39;./App.css&#39;

function App() {
  const name = &#39;react&#39;;
  return (
    &lt;&gt;
      &lt;div className=&quot;react&quot;&gt;{name}&lt;/div&gt;
      &lt;input /&gt;        // self-closing 태그
    &lt;/&gt;
  )
}

export default App;</code></pre>
<p><br><br></p>
<h4 id="9-주석">9. 주석</h4>
<p>&nbsp;JSX 안에서 주석을 작성하는 방법은 일반 자바스크립트에서 주석을 작성할 때와 다르다.</p>
<pre><code class="language-javascript">import &#39;./App.css&#39;

function App() {
  const name = &#39;react&#39;;
  return (
    &lt;&gt;
      {/* 주석은 이렇게 작성한다 */}
      &lt;div 
        className=&quot;react&quot;   // 시작 태그를 여러 줄로 작성한다면 &#39;//&#39;로 주석을 작성할 수 있다.
      &gt;
        {name}
      &lt;/div&gt;

        // 하지만 이런 주석이나
        /* 이런 주석은 페이지에 그대로 나타난다.

    &lt;/&gt;
  )
}

export default App;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[React 핵심개념 - Virtual DOM]]></title>
            <link>https://velog.io/@l-suyeon-l/React-%ED%95%B5%EC%8B%AC%EA%B0%9C%EB%85%90-Virtual-DOM</link>
            <guid>https://velog.io/@l-suyeon-l/React-%ED%95%B5%EC%8B%AC%EA%B0%9C%EB%85%90-Virtual-DOM</guid>
            <pubDate>Mon, 09 Sep 2024 11:28:38 GMT</pubDate>
            <description><![CDATA[<h3 id="dom이란">DOM이란?</h3>
<blockquote>
<p>Document Object Model의 약자로, 문서 객체 구조를 표현하는 방식</p>
</blockquote>
<p><br>&nbsp;DOM은 동적 UI에 최적화되어 있지 않다. 그렇기 때문에 DOM 자체는 빠르지만, 웹 브라우저 단에서 DOM에 변화가 일어나면 웹 브라우저가 CSS를 다시 연산하고, 레이아웃을 구성하고, 페이지를 리페인트하는 과정에서 많은 시간이 소요된다. 따라서 규모가 큰 웹 애플리케이션에서 DOM에 직접 접근하여 변화를 주다 보면 성능 이슈가 발생하기 시작한다. </p>
<br>

<h4 id="해결법">해결법</h4>
<p>&nbsp;성능 저하를 해결하기 위해 DOM을 최소한으로 저작하여 작업을 처리하는 방식으로 개선할 수 있다. 그것이 바로 <strong>Virtual DOM</strong> 방식이다.</p>
<p><br><br><br></p>
<h3 id="virtual-dom">Virtual DOM</h3>
<p>&nbsp;리액트에서는 실제 DOM에 접근하여 조작하는 대신, DOM을 추상화한 자바스크립트 객체 Virtual DOM을 구성하여 사용한다. 이를 통해 DOM 업데이트를 추상화함으로써 DOM 처리 횟수를 최소화하고 효율적으로 진행할 수 있다.
<br></p>
<h4 id="dom-업데이트의-3가지-절차">DOM 업데이트의 3가지 절차</h4>
<ol>
<li>데이터를 업데이트하면 전체 UI를 Virtual DOM에 리렌더링</li>
<li>이전 Virtual DOM에 있던 내용과 현재 내용 비교</li>
<li>바뀐 부분만 실제 DOM에 적용</li>
</ol>
<p><img src="https://velog.velcdn.com/images/l-suyeon-l/post/f5812ee8-7740-435c-ae7c-da302ec165c5/image.png" alt=""></p>
]]></description>
        </item>
    </channel>
</rss>