Mypy

Mypy는 Python 코드에 대해 정적 타입 검사를 수행하는 도구입니다.

이는 TypeScript의 컴파일러와 유사한 역할을 수행하며, 코드에서 타입 오류를 찾아내는 데 도움이 됩니다​.

 

예제:
먼저 mypy를 설치합니다:

pip install mypy


다음은 mypy를 사용한 Python 코드 예제입니다:(name에 대해 str이라는 어노테이션을 했음에 주목. python 3.5기능)

# 파일명: example.py

def greeting(name: str) -> str:
    return "Hello, " + name

age: int = "25"  # 이 줄은 타입 오류를 발생시킵니다.

print(greeting("Alice"))


터미널에서 mypy를 사용하여 코드를 검사합니다:

mypy example.py

이 명령을 실행하면, mypy는 age: int = "25"라인에서 타입 오류를 발견하고 이를 알려줍니다.

 


Pytype:

Pytype은 또 다른 Python 정적 타입 검사 도구.

어노테이션이 없어도 추론을 기반으로 동작함.

 

예를들어 아래와 같이 어노테이션이 없는 코드에 대해서 pytype을 수행하면

def multiply_numbers(a, b):
    return a * b

result = multiply_numbers(5, '3')
print(result)

아래처럼 런타임전 경고를 확인할 수 있음(런타임에서는  Python은 문자열 '3'을 5번 반복하여 '33333'을 생성하고 오류로 판단하지 않음)

$ pytype example.py
Computing dependencies
Analyzing 1 sources with 0 local dependencies
ninja: Entering directory `/Users/user/.pytype'
[1/1] check example
FAILED: /Users/user/.pytype/pyi/example.pyi 
pytype-single --imports_info /Users/user/.pytype/imports/example.imports --module-name example -V 3.8 -o /Users/user/.pytype/pyi/example.pyi --analyze-annotated --nofail --quick /Users/user/example.py
File "/Users/user/example.py", line 4, in <module>: unsupported operand type(s) for *: 'int' and 'str' [unsupported-operands]
  Function multiply_numbers was called with the wrong arguments (1:15)

For more details, see https://google.github.io/pytype/errors.html#unsupported-operands.
ninja: build stopped: subcommand failed.

 

Mypy vs Pytype

Mypy

Mypy는 Dropbox에서 개발되었으며, Python의 첫 번째 정적 타입 검사 시스템으로 간주됩니다.

이 도구는 2012년부터 개발이 시작되었으며, 아직도 활발하게 개발이 진행되고 있습니다​.
Mypy는 standalone으로 실행되거나, 커맨드 라인이나 편집기 또는 IDE의 linter 통합의 일부로 작동할 수 있습니다.
Mypy는 타입 어노테이션을 포함하지 않은 코드에 대해 대부분의 코드 검사를 수행하지 않으며, 이는 점진적으로 코드 기반을 주석 처리하고 있는 경우 Mypy가 시간을 낭비하지 않도록 하기 위함입니다.


Pytype

Pytype는 Google에서 개발되었으며, Mypy와 달리 타입 설명자 대신 추론을 사용합니다. 즉, Pytype는 코드 흐름을 분석하여 타입을 결정하려고 시도하며, 타입 어노테이션에 엄격하게 의존하지 않습니다​1.
Pytype는 가능한 한 관대하게 행동하며, 런타임에서 작동하고 어떤 어노테이션도 모순되지 않는 연산이 있으면 Pytype는 그것에 대해 불평하지 않습니다.
pytype의 reveal_type(expr)을 사용해서 런타임 전에 type()과 비슷한 기능을 활용하여 디버깅/개발 가능

 

 

반응형

'Programming > Python' 카테고리의 다른 글

pyenv를 통한 python버전 변경  (0) 2023.12.17
venv  (0) 2023.12.17
python 스트링 인코딩 핸들링  (0) 2021.11.30
Python GUI Programming(Tkinter)  (0) 2021.01.02
파이선환경 그리고 requirements.txt  (0) 2020.09.20

TypeScript vs ECMAScript

ECMAScript (ES):

ECMAScript는 JavaScript 언어의 표준 사양입니다.
ECMAScript는 JavaScript의 기본 구조와 규칙을 설정하며, JavaScript 엔진이 이 표준을 따라 구현되어야 합니다.
ECMA International이라는 표준화 기구가 관리하며, 시간이 지남에 따라 여러 버전의 ECMAScript 사양이 발표되었습니다 (예: ES3, ES5, ES6/ES2015 등).


TypeScript

TypeScript는 Microsoft에서 개발한 JavaScript의 상위 집합(superset) 언어입니다.
TypeScript는 JavaScript의 모든 기능을 포함하며, 그 위에 정적 타입 체크와 인터페이스, 제네릭, 데코레이터 등과 같은 추가 기능을 제공합니다.
정적 타입 체크는 코드의 오류를 런타임 전에 찾아내고, 코드의 가독성과 유지 관리성을 향상시킵니다.
TypeScript는 개발 시간에 TypeScript 코드를 JavaScript 코드로 변환(트랜스파일)하여 실행할 수 있도록 합니다. 이는 TypeScript 컴파일러를 사용하여 수행됩니다.


비교:

타입 시스템: TypeScript는 정적 타입 시스템을 제공하는 반면, ECMAScript(JavaScript)는 동적 타입 시스템을 사용합니다.
추가 기능: TypeScript는 ECMAScript의 기능에 추가적인 기능을 제공하여, 큰 프로젝트의 관리와 유지 보수를 돕습니다.
호환성: TypeScript는 JavaScript와 완벽하게 호환되며, TypeScript 코드는 JavaScript 코드로 변환될 수 있습니다.
표준화: ECMAScript는 국제 표준이며, TypeScript는 Microsoft에 의해 관리되는 오픈 소스 프로젝트입니다.

 

코드 샘플

// javascript
function add(a, b) {
    return a + b;
}

const result = add(5, '10');  // Output: '510' (문자열 연결)


//typescript
function add(a: number, b: number): number {
    return a + b;
}

const result = add(5, '10');  // Type Error: Argument of type 'string' is not assignable to parameter of type 'number'.

위의 TypeScript 코드에서 add 함수는 두 개의 숫자 타입 매개변수를 받아야 하며, 숫자 타입의 값을 반환해야 한다는 것을 명시적으로 지정합니다. 따라서, 문자열을 매개변수로 전달하려고 하면 컴파일 타임에 타입 에러가 발생합니다.

이 예제는 TypeScript의 정적 타이핑이 코드의 안정성을 어떻게 향상시키는지 보여줍니다. TypeScript는 개발자에게 잠재적인 문제를 미리 알려주어, 런타임 에러를 줄이고 코드의 품질을 향상시킵니다.

 

반응형

'Programming > frontend' 카테고리의 다른 글

local storage/session storage  (0) 2023.10.07

도입배경

 

2000년대 초반에는 웹 개발에서 주로 쿠키를 사용하여 클라이언트 측 데이터를 저장하곤 했습니다. 그러나 쿠키는 몇 가지 제약 사항과 문제점이 있었습니다. 예를 들어, 쿠키는 작은 용량의 데이터만 저장할 수 있고, 모든 HTTP 요청에 자동으로 포함되어 네트워크 부하를 초래할 수 있습니다.

이러한 문제를 해결하기 위해 HTML5 명세의 일부로 Local Storage와 Session Storage가 도입되었습니다. 이 기술은 2009년에 W3C에 의해 표준화되었고, 대부분의 현대 웹 브라우저에서 지원됩니다

 

.

Local Storage와 Session Storage의 주요 특징:


클라이언트 측 저장: 이들은 클라이언트 측에서만 접근 가능하며, 서버로 전송되지 않습니다. 이로 인해 네트워크 부하가 줄어듭니다.

용량: 일반적으로 5~10MB의 데이터를 저장할 수 있어, 쿠키보다 훨씬 더 많은 정보를 저장할 수 있습니다.

API: JavaScript를 통해 간단하게 데이터를 저장하고 검색할 수 있는 API가 제공됩니다.

Session Storage는 탭이나 창이 닫힐 때까지 데이터를 유지하며, Local Storage는 영구적으로 데이터를 저장합니다.

Local Storage는 도메인, 프로토콜, 그리고 포트까지 모두 일치해야만 데이터에 접근할 수 있기 때문에, 포트가 다른 두 서비스에서는 Local Storage를 공유할 수 없습니다. 

 

 

코드 샘플

// Local Storage에 정보 저장
localStorage.setItem('isLoggedIn', 'true');

//Local Storage에서 정보 불러오기
const storedIsLoggedIn = localStorage.getItem('isLoggedIn');

 

브라우저에서 확인

크롬에서 F12를 누르고 애플리케이션탭 > 왼쪽탭에서 로컬 스토리지를 보면 다음처럼 내용 확인이 가능하다.

반응형

'Programming > frontend' 카테고리의 다른 글

TypeScript  (0) 2023.10.07

생성 패턴 (Creational Patterns)
생성 패턴은 객체 생성과 관련된 문제를 해결합니다.

싱글턴 패턴 (Singleton Pattern): 클래스의 인스턴스가 하나만 생성되도록 보장.
팩토리 메서드 패턴 (Factory Method Pattern): 객체 생성을 서브클래스에 위임.
빌더 패턴 (Builder Pattern): 복잡한 객체를 단계별로 생성합니다.

  • 생성자의 인수가 너무 길고 복잡할때 이를 보완.
  • method chaining 과 함께 사용


프로토타입 패턴 (Prototype Pattern): 기존 객체를 복제하여 새 객체를 생성합니다.

  • python deepcopy()


구조 패턴 (Structural Patterns)

구조 패턴은 클래스나 객체의 구성을 단순화하고 확장성을 높입니다.

어댑터 패턴 (Adapter Pattern): 호환되지 않는 인터페이스를 변환하여 함께 작동하게 합니다.

  • 바꾸기 힘든 레거시를 품은 새로운 클래스 만들어서 기존 구조와 통합


브리지 패턴 (Bridge Pattern): 구현부에서 추상화를 분리하여 독립적으로 변화할 수 있게 합니다.

  • 잘 안쓰는듯? abstract 와 interface 사이에 다르를 놓는것 같은데..


컴포지트 패턴 (Composite Pattern): 객체들을 트리 구조로 구성하여 부분-전체 계층을 표현합니다.

  • 단일요소와 집합요소를 모두 같은 부모를 상속 받도록 해서 복잡한 트리구조도 단일 개체로 표현가능
  • Folder와 File이 모두 Unit이라는 부모를 상속받도록 하는 것 생각


데코레이터 패턴 (Decorator Pattern): 객체에 동적으로 새로운 책임을 추가합니다.
퍼사드 패턴 (Facade Pattern): 복잡한 시스템에 대한 간단한 인터페이스를 제공합니다.

  • 이건 그냥 복잡한 단계를 하나의 API로 묶어서 단순화 하는 개념.


플라이웨이트 패턴 (Flyweight Pattern): 공유를 통해 대량의 객체를 효율적으로 지원합니다.
프록시 패턴 (Proxy Pattern): 다른 객체에 대한 대리자나 플레이스홀더 역할을 합니다.

  • 준비시간이 오래걸리는 프린터 앞에 버퍼프린터 대리자로 모아서 처리하는거 생각하면 됨


행동 패턴 (Behavioral Patterns)
행동 패턴은 객체 간의 책임과 알고리즘을 관리합니다.

책임 연쇄 패턴 (Chain of Responsibility Pattern): 요청을 객체의 체인을 통해 전달합니다.
명령 패턴 (Command Pattern): 요청을 객체로 캡슐화합니다.

  • 행동도 객체화 할수 있다는 것(포토샵 액션 리스트 생각)


해석자 패턴 (Interpreter Pattern): 문법 규칙을 클래스로 표현합니다.

  • 컴파일러 비슷한일 할때, 클래스로 처리


반복자 패턴 (Iterator Pattern): 컬렉션의 요소를 순회하는 방법을 제공합니다.
중재자 패턴 (Mediator Pattern): 객체 간의 상호작용을 캡슐화하여 객체들이 직접 참조하지 않도록 합니다.
메멘토 패턴 (Memento Pattern): 객체의 상태를 캡쳐하고 복원합니다.
감시자 패턴 (Observer Pattern): 객체 간의 일대다 의존성을 정의합니다.

  • 구독하면 알림보내는거 생각하면됨. 이벤트일 필요없고 콜백도 가능


상태 패턴 (State Pattern): 객체의 내부 상태에 따라 행동을 변경합니다.

  • 상태를 객체로 표현하여, 조건문처리를 단순화 한다.


전략 패턴 (Strategy Pattern): 알고리즘을 캡슐화하여 상호 교체 가능하게 합니다.

  • 암것도 아님. 추상화를 통해 sum()등의 행동을 갈아 끼울 수 있다는 것.


템플릿 메서드 패턴 (Template Method Pattern): 알고리즘의 구조를 정의합니다.
방문자 패턴 (Visitor Pattern): 객체 구조에 새로운 연산을 추가합니다.

  • 데이터와 행동을 클래스 분리. 이렇게 하면 행동의 추가 확장이 편해짐(sum, avg등)
반응형

'Programming' 카테고리의 다른 글

yaml  (0) 2024.03.02
라즈베리파이 초기 세팅  (0) 2023.01.20
STL lower_bound, upper_bound  (0) 2020.04.12

주 역할

웹서버/캐시/로드밸런서/리버스프록시

 

SSL Termination

클라이언트와는 https통신을 하면서 백단 서버들과는 http(gRPC포함)통신을 하여, 복호화 부담을 줄이는 기능

 

실전꿀팁

여기가면 실제로 많이 사용되는 Nginx설정을 보고 적용할 수 있다.

반응형

'Programming > Linux' 카테고리의 다른 글

docker network  (0) 2023.10.29
docker-compose  (0) 2023.10.28
Redis  (0) 2023.08.10
kafka 설치(우분투 기존)  (0) 2023.07.31
ELK연습  (0) 2023.07.30

일반적으로 셔플 알고리즘을 떠올리면 다음과 같은 naive solution을 생각하기 쉽다.

void LnNumber::ShuffleArray(long* arr, long count)
{
      for (int i=0;i<count;i++)
      {
            long toInx = rand() % count;
            {//swap
                  long temp = arr[i];
                  arr[toInx] = arr[i];
                  arr[i] = temp;
            }
      }
}

하지만 위 코드는 순진해보이는 겉모습과 다르게 엄청난 바이어스를 포함하고 있는데,

카드 3장의 모든 순열은 3!(=3 x 2 x 1) = 6이지만 위의 toInx를 보면 3 x 3 x 3 = 27로 6으로 나눠떨어지지 않는 경우의 수를 가지고 있다!

 

따라서 아래처럼 덜 직관적이지만 n!에 맞춘 경우의 수를 가진 코드로 수정해줘야 한다.

이 코드를 Fisher-Yates shuffle이라고 한다.

void LnNumber::ShuffleArray(long* arr, long count) {
    for (int i = count - 1; i > 0; i--) {
        long toInx = rand() % (i + 1); // 0부터 i까지의 랜덤한 인덱스(i포함)
        // swap
        long temp = arr[i];
        arr[i] = arr[toInx];
        arr[toInx] = temp;
    }
}

이코드의 toInx를 보면 카드3장의 예시에서 3 x 2 x 1 = 6 = 3!의 경우의 수를 가진다.

 

sort

가장 기본적인 sort는 Array.sort()또는 Collections.sort()를 쓰면 된다. (char[] 같은건 전자만 가능한듯?)

struct node 같은걸 쓰면서 특정 필드에 대해 소팅하고 싶으면 다음 기법을 쓰자.

class Tweet {
    Long time;
    int tweetId;
}
List<Tweet> feed;
...

//time에 대해서 sort하고 싶을때
feed.sort((t1, t2) -> t1.time.compareTo(t2.time));  
//역순을 원하면 t1, t2를 바꿔준다.
feed.sort((t1, t2) -> t2.time.compareTo(t1.time));

//약간 올드하게 아래처럼도 가능
Collections.sort(feed, new Comparator<Tweet>() {
    @Override
    public int compare(Tweet t1, Tweet t2) {
        return t1.time.compareTo(t2.time);
    }
});

여러 필드에 대해서 복잡하게 정렬해야하면 아래 방법 사용

feed.sort(Comparator.comparing((Tweet t) -> t.time)
                   .thenComparing(Comparator.comparing((Tweet t) -> t.tweetId).reversed()));
반응형

LIS(Longest Increasing Subsequence)는 가장 긴 증가하는 부분 수열을 찾는 알고리즘이다.

즉, 주어진 수열에서 일부 숫자를 제거하여 만든 부분 수열 중에서, 오름차순으로 정렬된 가장 긴 수열을 찾는 문제.
예를 들어, 수열 [10, 20, 10, 30, 20, 40]이 있다면, LIS는 [10, 20, 30, 40]이 된다.

예시 백준 문제는 여기 있다.

DP를 연습할때 가장 먼저 나오는 문제이지만, 의외로 2가지 실수하기 쉬운 포인트와. 한가지 인사이트를 제공한다.

 

2가지 실수하기 쉬운 포인트

아래는 이문제에 대한 정답코드인데, 아래 주석으로 여기라고 되어 있는 부분을 풀때마다 실수했다.

#include <stdio.h>
#include <algorithm>
using namespace std;

// dp[3] = 5 ; 인덱스 3까지 가장 긴 증가하는 부분수열의 길이는 5이다.
int dp[1001]; 
int A[1001];

int main(void)
{
	int N; scanf("%d", &N);
	for (int i = 0; i < N; i++) scanf("%d", A + i),dp[i]=1;  // 여기. dp[i]=1초기화 부분!
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < i; j++) {
			if (A[i] > A[j]) 
				dp[i] = max(dp[i], dp[j] + 1);
		}
	}
	int ans = 1;
	for (int i = 0; i < N; i++) ans = max(ans, dp[i]);  // 여기. dp[n-1]아니어도 답이 될 수 있음!
	printf("%d\n", ans);
	return 0;
}

 

한가지 인사이트

이 문제는 놀랍게도 recursive+memoization보다 iterative 방식이 더 생각하기 편하고,

편한 recursive+memoization을 떠올리면 dp[ix][cur_val] 형태가 돼서 냅색DP형태가 나오는데 문제 범위에 따라 메모리초과 오류가 발생하여 해결이 어렵다.

아래는 편한 recursive버전이다.

#include <bits/stdc++.h>
using namespace std;
int dp[1001][1001];
int in[1001];
int n;
int dfs(int ix, int cur_max_val){
    if(ix>=n) return 0;
    if(dp[ix][cur_max_val]) return dp[ix][cur_max_val];
    
    //포함
    int r1 = -1;
    if(cur_max_val < in[ix])
        r1= 1 + dfs(ix+1, in[ix]);
    
    //불포함
    int r2 = dfs(ix+1, cur_max_val);

    return dp[ix][cur_max_val] = max(r1,r2);
}
int main() {
    scanf("%d", &n);
    for(int i=0;i<n;i++) scanf("%d", in+i);
    printf("%d\n", dfs(0, 0));

    return 0;
}

자세히 들여다 보면, dp[n]을 1로 초기화 하는 부분도 필요없고, 마지막에 정렬하는 부분도 필요없어서 실수 확률이 확연히 줄어든다.

하지만 위 코드를 dp[ix]로 1차원만 사용하도록 변경하는건 쉽지 않다.

아래처럼 할 수 있긴한데, dfs함수내에 iterative한 부분이 들어 있어 완전한 DFS라고 부를 수 있을지 약간 애매하다.

#include <bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for(int i=(a);i<(b);++i) 
#define REP(i,n) FOR(i,0,n) 
typedef vector<int> VI;

int dp[1001];
int in[1001];
int N;
int go(int n)
{
         if(n==0) return 1;
         if(dp[n]) return dp[n];
 
         int maxR=1;
         REP(i,n){
            if(in[n] >in[i])
                maxR = max(maxR, go(i)+1);                 
         }
         return dp[n] = maxR;
}
 
int main()
{
        scanf("%d\n", &N);
        REP(i, N)scanf("%d",&in[i]); 
        int r=0;
        REP(i,N) r=max(r,go(i));
        cout << r <<endl;
        return 0;
}

 

실제 시퀀스를 출력하는 방법

아래처럼 prev배열하나를 추가하면 어렵지 않게 구현가능하다.

#include <stdio.h>
#include <algorithm>
using namespace std;

// dp[3] = 5 ; 인덱스 3까지 가장 긴 증가하는 부분수열의 길이는 5이다.
int dp[1001];
int A[1001];
int prv[1001];

int main(void)
{
    fill(prv, prv + 1001, -1);
    int N;
    scanf("%d", &N);
    for (int i = 0; i < N; i++)scanf("%d", A + i), dp[i] = 1; // 여기. dp[i]=1초기화 부분!
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < i; j++)
        {
            if (A[i] > A[j])
                if (dp[j] + 1 > dp[i])
                {
                    dp[i] = dp[j] + 1;
                    prv[i] = j;
                }
        }
    }
    int ans = 1;
    int end_ix = 0;
    for (int i = 0; i < N; i++)
    {
        if (ans < dp[i])
        {
            ans = dp[i];
            end_ix = i;
        }
    }
    printf("%d\n", ans);
    vector<int> v;
    v.push_back(A[end_ix]);
    while (prv[end_ix] != -1)
    {
        end_ix = prv[end_ix];
        v.push_back(A[end_ix]);
    }
    reverse(v.begin(), v.end());
    for (auto e : v)
        printf("%d ", e);

    return 0;
}
반응형

'Programming > Algorithm' 카테고리의 다른 글

배열 제대로 shuffle 하기 (Fisher-Yates shffle)  (0) 2023.08.13
기하 - 2선분의 교차점 구하기  (0) 2023.07.25
meet in the middle 알고리즘  (0) 2022.03.02
투 포인터  (0) 2022.03.01
이분 그래프(Bipartite Graph)  (0) 2022.02.22

time

long currentTime = System.currentTimeMillis();

 

표준입출력처리

leetcode
2
leet code

아래 예시는 위 인풋을 처리할 수 있다.

import java.util.*
public class coupang1 {
    public static void main(String args[]){
        Scanner scanner = new Scanner(System.in);
        String s = scanner.nextLine(); // 문자열 s 입력
        int n = Integer.parseInt(scanner.nextLine()); // 사전 단어의 개수 입력
        String[] wordDictArray = scanner.nextLine().split(" "); // 공백으로 구분된 사전 단어 입력
        List<String> wordDict = Arrays.asList(wordDictArray); // 배열을 리스트로 변환
        
    }
}

Scanner로 속도가 느릴때

인풋개수가 클때는 Scanner가 느릴 수 있다. 이때 bufferedReader를 쓰면 몇 배 빠르게 할 수 있다.

// before
Scanner sc = new Scanner(System.in);
int n = sc.nextInt()
List<Integer> arr = new ArrayList<>();
for(int i=0;i<n;i++) arr.add(sc.nextInt());

// after
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
List<Integer> arr = new ArrayList<>();
StringTokenizer st = new StringTokenizer(br.readLine());
for (int i = 0; i < n; i++) arr.add(Integer.parseInt(st.nextToken()));

 

자료구조 관련

LinkedList 사용하기

헷갈리는 linkedList사용법을 정리한다.

예시문제:
두 개의 정렬된 연결 리스트로부터 중앙값을 계산하십시오.
예시 1:
L1 = 1 -> 3
L2 = 2
중앙값은 2.0입니다.
예시 2:
L1 = 1->2
L2 = 3->4
중앙값은 (2+3)/2 = 2.5입니다.

input1:
2
1 2
1
3
output1:
2.0

input2:
3
1 3 5
3
2 4 6
output2:
3.5

솔루션

import java.util.*;
public class Main {
    public static void main(String args[]){
        LinkedList<Integer> list1 = new LinkedList<>();
        LinkedList<Integer> list2 = new LinkedList<>();
        Scanner sc = new Scanner(System.in);
        int n1 = sc.nextInt();
        for(int i=0;i<n1;i++) list1.add(sc.nextInt());  // 추가는 add()
        int n2 = sc.nextInt();
        for(int i=0;i<n2;i++) list2.add(sc.nextInt());
        int N = n1+n2;
        //합친 리스트의 개수가 홀수개이면 n/2 번째인덱스
        //짝수개이면 n/2-1, n/2번째 인덱스의 평균이 답
        int mid_six = N%2==1?N/2:N/2-1;
        int mid_eix = N%2==1?N/2:N/2;

        ListIterator<Integer> it1 = list1.listIterator();  // next()하려면 Iterator필요
        ListIterator<Integer> it2 = list2.listIterator();
        int median1 = 0, median2 = 0;
        for (int i = 0; i <= mid_eix; i++) {
            int v1 = it1.hasNext() ? it1.next() : Integer.MAX_VALUE;  // hasNext()눈여겨 보자
            int v2 = it2.hasNext() ? it2.next() : Integer.MAX_VALUE;

            int value;
            if (v1 < v2) {
                value = v1;
                if (v2 < Integer.MAX_VALUE) it2.previous();  // previous()도 가능
            } else {
                value = v2;
                if (v1 < Integer.MAX_VALUE) it1.previous();
            }

            if (i == mid_six) median1 = value;
            if (i == mid_eix) median2 = value;
        }
        System.out.println((double)(median1 + median2) / 2.0);
        sc.close();
    }
}

LinkedList 선언부, ListIterator, next()/previous() 처리 등을 눈여겨 보자. 

근데 사실 이 문제의 경우에는 꼭 LinkedList를 쓸필요는 없다. ArrayList로도 충분.

ArrayList

c++ vector에 해당하며 다음과 같이 쓸 수 있다.

ArrayList<Integer> list = new ArrayList<>();
list.add(10);
list.add(20);
int value = list.get(1); // 20을 가져옵니다.

c++과 다르게 list[1]등으로 배열인덱스는 쓰지 못함에 주의

 

HashMap

c++ map에 해당하며 다음과 같이  쓸 수 있다.

HashMap<Integer, String> map = new HashMap<>();
HashMap<Integer, List<Integer>> map2 = new HashMap<>();
for (int i = 0; i < N; i++) {
    String a = map.getOrDefault(C[i],"");
    List<Integer> b = map2.getOrDefault(C[i],new ArrayList<>());
    a+=S[i];map.put(C[i],a);
    b.add(i);map2.put(C[i],b);
}

getOrDefault()에 주목해보자. 이걸안쓰고 get()을 쓰면 항상null체크를 해줘야 한다.

(C++의 std::map에서는 요청한 키가 존재하지 않으면 해당 키를 자동으로 생성하고 해당 값 타입의 기본 생성자를 호출하여 값을 초기화)

containKey(key)를 쓰면 put()했는지 체크할 수 있다. (c++에서 map.count()와 같은 기능)

 

iteration하기

다음 4가지 정도 방법이 있다.

//방법1. 전통적인 방법.. Entry개념때문에 복잡하다.
    int total_anagrams = 0;
    Iterator<Map.Entry<String,Integer>> iterator = ana_map.entrySet().iterator();
    int total_anagrams = 0;
    while(iterator.hasNext()){
      Map.Entry<String, Integer> entry = iterator.next();
      total_anagrams += entry.getValue();
    }
    
//방법2. key나 value한쪽만 필요한 경우 다음처럼 간략화 가능
    int total_anagrams = 0;
    for (Integer value : ana_map.values()) {
      total_anagrams += value;
    }
    
//방법3. key나 value 둘다 필요하면서 약간 더 간단한 방법
for (Map.Entry<String, Integer> entry : ana_map.entrySet()) {
  String key = entry.getKey();
  Integer value = entry.getValue();
  // key와 value를 사용한 작업
}

//방법4. 조금 더 간단한 방법(람다 표현식)
ana_map.forEach((key, value) -> {
  // key와 value를 사용한 작업
});

 

Queue

이 문제에 대한 솔루션인데, 단순한 BFS로 풀린다.

queue사용법을 눈여겨보자(add, poll, size)

class Solution {
    private void check(Queue<Integer> q, int[][] mat, int[][] dist, int py, int px, int y, int x){
        int h = mat.length;
        int w = mat[0].length;
        if(y<0||y>=h) return;
        if(x<0||x>=w) return; 
        if(dist[y][x]>dist[py][px] + 1) {
            dist[y][x] = dist[py][px]+1;
            q.add(y);
            q.add(x);
        }
    }
    public int[][] updateMatrix(int[][] mat) {
        int h = mat.length;
        int w = mat[0].length;
        int[][] dist = new int[h][w];

        Queue<Integer> q = new ArrayDeque<>();
        for(int y=0;y<h;y++)for(int x=0;x<w;x++)dist[y][x]=Integer.MAX_VALUE;
        for(int y=0;y<h;y++)for(int x=0;x<w;x++){
            if(mat[y][x]==0) {
                dist[y][x]=0;
                q.add(y);q.add(x);
            }
        }
        while(q.size()>0){
            int cy = q.poll();
            int cx = q.poll();
            check(q,mat,dist,cy,cx,cy-1, cx);
            check(q,mat,dist,cy,cx,cy+1, cx);
            check(q,mat,dist,cy,cx,cy, cx-1);
            check(q,mat,dist,cy,cx,cy, cx+1);
        }
        return dist;
    }    
}

 

Stack

c++과 비슷하게 push(), pop()인데 pop()이 top()+pop()이라고 보면된다. (값을 리턴하면서 즉시 pop도 하는..)

top()만 하려면 peek()를 쓰면된다.(아래 샘플엔 없다)

아래 샘플참조..

import java.util.*;

public class StackStringDecoder {
    
    public static String decodeString(String s) {
        Stack<Integer> stack_repeat = new Stack<>();
        Stack<String> stack_str = new Stack<>();
        String ret_str = new String("");
        int repeat = 0;
        for(int i=0;i<s.length();i++){
            char c = s.charAt(i);
            if(Character.isDigit(c)){
                repeat *= 10;
                repeat += c-'0';
            }else if(c=='['){
                stack_repeat.push(repeat);  // push하는 부분
                stack_str.push(ret_str);
                ret_str = "";
                repeat = 0;
            }else if(c==']'){
                String pop_str = stack_str.pop();  // pop하는 부분
                repeat = stack_repeat.pop();
                for(int j=0;j<repeat;j++)
                    pop_str += ret_str;
                ret_str = pop_str;
                //repeat = 0;
            }else{
                assert(Character.isAlphabetic(c));
                ret_str+=c;
            }
        }
        return ret_str;
    }

    public static void main(String[] args) {
        System.out.println(decodeString("3[a2[c]]")); // "accaccacc"
        System.out.println(decodeString("3[a]2[bc]")); // "aaabcbc"
        System.out.println(decodeString("2[abc]3[cd]ef")); // "abcabccdcdcdef"
        System.out.println(decodeString("2[a3[b]]")); // "abbbabbb"
        System.out.println(decodeString("1[ab2[c]]")); // "abcc"
    }
}

char[]

String은 immutable이라 글자단위로 수정하려면 char[]로 변환해주어야 한다.

char[] chars = myString.toCharArray(); //String에서 char[]로 변환
String myString = new String(chars);  //char[]에서 String으로 변환

한번 println의 경우는 다음과 같이 String으로 변환해주지 않으면 주소가 출력된다.

char[] result = {'H', 'e', 'l', 'l', 'o'};
System.out.println(new String(result)); // "Hello"를 출력합니다.

 

리턴값이 2개 필요할때

아래처럼 int[] r = func(); 해서 r[0], r[1]을 쓰면된다.

static int[] parseNumber(String s, int ix) {
    int number = 0;
    while (ix < s.length() && Character.isDigit(s.charAt(ix))) {
        number = number * 10 + (s.charAt(ix) - '0');
        ix++;
    }
    return new int[] {number, ix};
}

public static void main(String[] args) {
    String expression = "12345+6789";
    int ix = 0;

    int[] result = parseNumber(expression, ix);
    int parsedNumber = result[0];
    int nextIndex = result[1];

    System.out.println("Parsed number: " + parsedNumber); // 출력: Parsed number: 12345
    System.out.println("Next index: " + nextIndex);       // 출력: Next index: 5
}

 

String 핸들링

시간과 같이 특정 글자로 split할때는 아래코드 참조하자(아래는 12포맷을 AM, PM글자 떼버리고 24포맷으로 바꾸는 코드이다)

자바는 아예 split()함수가 있어서 오히려 c++보다 수월하다.

public class Main {
    public static void main(String[] args) {
        String inputTime = "07:05:45PM";
        String outputTime = timeConversion(inputTime);
        System.out.println(outputTime); // 출력: 19:05:45
    }

    public static String timeConversion(String s) {
        String[] timeParts = s.substring(0, 8).split(":");
        int hour = Integer.parseInt(timeParts[0]);

        if (s.endsWith("PM") && hour != 12) {
            hour += 12;
        } else if (s.endsWith("AM") && hour == 12) {
            hour = 0;
        }

        return String.format("%02d:%s:%s", hour, timeParts[1], timeParts[2]);
    }
}

참고삼아 c++버전도 기록해둔다.

#include <iostream>
#include <sstream>
#include <iomanip>

std::string timeConversion(const std::string& s) {
    int hour, minute, second;
    char colon, am_pm;
    std::istringstream ss(s.substr(0, 8));
    ss >> hour >> colon >> minute >> colon >> second;

    if (s.find("PM") != std::string::npos && hour != 12) {
        hour += 12;
    } else if (s.find("AM") != std::string::npos && hour == 12) {
        hour = 0;
    }

    std::ostringstream result;
    result << std::setw(2) << std::setfill('0') << hour << ":"
           << std::setw(2) << std::setfill('0') << minute << ":"
           << std::setw(2) << std::setfill('0') << second;

    return result.str();
}

int main() {
    std::string inputTime = "07:05:45PM";
    std::string outputTime = timeConversion(inputTime);
    std::cout << outputTime; // 출력: 19:05:45
    return 0;
}

sort

기본적인 sorting법

Array의 경우 다음과 같이 Arrays.sort() 또는 Collections.sort()를 쓴다.

import java.util.Arrays;

public class SortArrayExample {
    public static void main(String[] args) {
        int[] numbers = {5, 2, 8, 1, 3, 7};
        // 배열 정렬
        Arrays.sort(numbers);  // 이경우는 Collections.sort()는 못쓴다.
        // 정렬된 배열 출력
        System.out.println("Sorted array: " + Arrays.toString(numbers));
    }
}

역순으로 정렬하려면 다음과 같이 한다.

// 기본 배열은 Collections를 지원하지 않고 reverseOrder()도 사용할 수 없다.
// 따라서 List<Integer>로 변환후 수행한다.
Integer[] numbers = {5, 2, 8, 1, 3, 7};
List<Integer> number_list = Arrays.asList(numbers);
Collections.sort(number_list, Collections.reverseOrder());  // 이경우는 Collections.sort()는 못쓴다.
System.out.println("Sorted array: " + Arrays.toString(numbers));

구조체 정렬시 특정 필드에 대해 정렬하기

class Tweet {
    Long time;
    int tweetId;
}
List<Tweet> feed;
...
//time필드에 대해 정렬
feed.sort((t1, t2) -> t1.time.compareTo(t2.time));

//time필드에 대해 역순정렬
feed.sort((t1, t2) -> t2.time.compareTo(t1.time));

//아래처럼 전통적인 compare함수를 쓸 수도 있다.
Collections.sort(feed, new Comparator<Tweet>() {
    @Override
    public int compare(Tweet t1, Tweet t2) {
        return t1.time.compareTo(t2.time);
    }
});


//먼저 time에 대해 역순정렬하고, tweetId에 대해서 정방향정렬하기
feed.sort(Comparator.comparing((Tweet t) -> -t.time)
                   .thenComparing(t -> t.tweetId));
//방법2
feed.sort(Comparator.comparing((Tweet t) -> t.time)
                   .thenComparing(Comparator.comparing((Tweet t) -> t.tweetId).reversed()));
//방법3
feed.sort(Comparator.comparing((Tweet t) -> t.time)
                   .thenComparing((t1, t2) -> t2.tweetId - t1.tweetId));


//올드스쿨
feed.sort(new Comparator<Tweet>() {
    @Override
    public int compare(Tweet o1, Tweet o2) {
        if (o1.time != o2.time) {
            return o2.time - o1.time; // time에 대해 역순 정렬
        }
        return o1.tweetId - o2.tweetId; // tweetId에 대해 정방향 정렬
    }
});
반응형

설치 운영

우분투에서 설치

sudo apt-get update
sudo apt-get install redis-server

 

트러블슈팅

docker안에서 host의 redis에 접근하도록 하기

실행할때 다음처럼 --network host만 붙여주면 된다.

#!/bin/bash

PORT=$1

docker run \
  --network host \
  -e SPRING_APPLICATION_JSON='{"server":{"port":'"$PORT"'}}' \
  -p $PORT:$PORT \
  auth-service

 

설계관점

 

읽는 경우: Look aside Cache

Cache에 있으면 Cache에서 가져오고 없으면 DB에서 읽고 Cache 업데이트

 

쓰는경우: Write Back

Cache에 저장하고 주기적으로 모아서 DB에 배치업데이트. 

반응형

'Programming > Linux' 카테고리의 다른 글

docker-compose  (0) 2023.10.28
Nginx  (0) 2023.08.16
kafka 설치(우분투 기존)  (0) 2023.07.31
ELK연습  (0) 2023.07.30
스팍 - 실습 - 웹서버 세션분석  (0) 2023.07.30

F5를 눌러서 라인디버깅이 가능한 디버거를 띄우기 위해서는,

 

먼저 package.json에서 다음 부분을 수정해준다.

  "scripts": {
    "dev": "NODE_OPTIONS='--inspect' next dev",
    ...
  },

그 다음, vscode에서 launch.json을 만든다음(이건 그냥 F5누르고 node.js눌러도 기본템플릿은 만들어준다.)

다음 내용을 써준다.

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "Launch Next.js",
            "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/next",
            "cwd": "${workspaceRoot}",
            "console": "integratedTerminal",
            "internalConsoleOptions": "neverOpen",
            "skipFiles": ["<node_internals>/**"]
        },
    ]
}

위처럼 하면 기본적인 디버깅환경은 구축이 된 것이고, Ctrl+F5로 실행하면  break포인트가 잡히지 않는다.

 

하지만 론치과정이 단순히 npm run dev하는 것 보다는 헤비하기 때문에 Ctrl+Shift+B를 눌러서 가볍게 실행하고 싶으면,

다음처럼 launch.json과 같은곳에 tasks.json을 만들어 준다.

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Run Next.js Without Debugging",
            "type": "shell",
            "command": "npm",
            "args": ["run", "dev"],
            "problemMatcher": [],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}

 

반응형

'Programming > node.js' 카테고리의 다른 글

react/next.js환경에서 http에서 https로 변경하기  (0) 2023.10.12

+ Recent posts