defaultdict()

- 숫자, list, set, 등으로 초기화 가능

- dictionary와 작동방식이 거의 동일한데, defaultdict()는 인자로 주어진 객체(default-factory)의 기본값을 dictionary 값의 초기값으로 지정할 수 있음

 

외부함수이기 때문에 import 

from collections import defaultdict

예시 1

A = [2,4,3,1,4,2]
A_dict = defaultdict(int)
for i in A:
	A_dict[i] += 1  # 일반적인 dictionary와 다른 부분
    
# A에서 개수가 1개인 값 찾기 (3과 1)
for k, v in A_dict.items():
	if v == 1:
    	print("unique")

defaultdict를 사용하지 않을 경우, 키가 있는지 확인하고 없으면 0으로 초기값 할당 후에 1을 더해야 함

 

- Codility "FirstUnique" 문제에서 사용

'Programming Language > 기타 언어(C\C++\C#\Python)' 카테고리의 다른 글

[Python] 입출력  (0) 2021.07.17
[C#] 연산- 소수점 나타내기  (0) 2021.04.07
[C] C Language Overview  (0) 2020.08.25
[C++] 접근자와 설정자  (0) 2020.06.14
[C++] 객체의 동적 생성  (0) 2020.06.14

코딩테스트를 파이썬으로 준비해보려고 오랜만에 파이썬을 만지작만지작 해보는데 걸리는게 많다...

책이나 프로그래머스 문제를 파이썬으로 풀면서 막히던 문법을 차례로 정리할 예정!

 

가장 기본적이었던 것.. 입력

 

입력의 기본

# 숫자 입력받기

파이썬에서 데이터를 입력받는 방법 : input( )

정수형 데이터로 처리하기 위해서는 앞에 int( ) 함수를 사용

n = int(input())

 

# 공백을 기준으로 구분하여 변수에 각각 정수형으로 저장하기 

map( )함수를 사용하여 각각 매핑하기라고 생각하면 됨

split( )를 이용하여 공백으로 구분하고 int를 앞에 적음으로써 정수형으로 저장

n,m,k = map(int,input().split())

 

# 여러개의 숫자를 입력받아 공백으로 구분하여 리스트 형태로 저장하기 ★★

input( )으로 입력받은 문자열을 공백으로 구분하기 위해서 split( )함수를 사용

공백으로 나눈 리스트로 바꾼 뒤에(list( )함수 사용) map( )을 이용하여 리스트의 모든 원소에 int( )함수를 적용

입력 받은 문자열을 공백으로 구분하여 각각 숫자 자료형으로 저장할 수 있도록 한다.

data = list(map(int, input().split()))

더 빠른 입력!

input( ) 대신 sys 라이브러리에 정의되어 있는 sys.stdin.readline( )함수 사용

sys.stdin.readline( )함수를 통해 sys 라이브러리를 사용할 때는 한 줄 입력 받음

readline( )을 입력하면 Enter를 치면 줄 바꿈 기호로 입력이 되는데, 이를 제거하기 위해 rstrip( )를 사용

 

import sys
data = sys.stdin.readline().rstrip()

 

출력의 기본

출력할 때, 단순히 print()만 쓰면 됨

print( )쓰면 출력되면서 줄바꿈이 자동으로 수행됨

a = 1
print(a)

 

"TypeError : can only concatenate str (not "int") to str"

자바에서 처럼 + 연산자를 이용하여 문자열과 수를 더하려고 하면 오류가 발생!

 

해결 방안

1) str( )함수 이용 : 출력하고자 하는 변수 데이터를 문자열로 변경

2) 콤마(,) 이용 : 각 자료형을 콤마를 기준으로 구분하여 출력

3) f-string 이용 : 문자열 앞에 접두사 f를 붙임으로써 중괄호 안에 변수를 넣으면 됨

answer = 7

#해결방안 1
print("정답은 "+str(answer)+"입니다")

#해결방안 2
print("정답은",str(answer),"입니다")

#해결방안 3
print(f"정답은 {answer}입니다")

→ 참고로 해결방안 1의 경우, 두 문자열 사이에 공백을 넣기 위해서는 직접 코드에 넣어야 하지만, 해결방안 2의 경우에는 넣지 않아도 공백이 자동 입력 된다

 

 

float answer;
answer = 15/6;
Debug.Log(answer);

answer가 int형이든 float형이든 동일하게 2로 나온다. 

 

소수점까지 나타내려면

float answer;
answer = 1.0f * 15/6;
Debug.Log(answer);

계산하는 과정 앞에 1.0f 를 곱해주면 된다. 

 

'Programming Language > 기타 언어(C\C++\C#\Python)' 카테고리의 다른 글

[Python] 유사 딕셔너리 defaultdict()  (0) 2022.06.18
[Python] 입출력  (0) 2021.07.17
[C] C Language Overview  (0) 2020.08.25
[C++] 접근자와 설정자  (0) 2020.06.14
[C++] 객체의 동적 생성  (0) 2020.06.14

C언어의 특징

1. UNIX 운영체제의 개발 도중 프로그래머에 의해 만들어짐

2. High-level과 Low-level language의 장점을 포함함

 - 기계어에 준하면서 고급 프로그래밍 언어로 집적된 표현 가능함

 - middle-level lang

3. 절차 지향적

4. 간결하고 범용성이 좋음

5. 메모리를 적게 사용함

6. 표준 라이브러리를 제공하며, 이식성이 뛰어남

7. 다른 프로그램 언어와 함께 혼합되어 기사용이 가능함

 

C언어의 단점

1. 완전한 고급언어에 비해서 상대적으로 배우기 쉽지 않음

2. UNIX가 가진 단점을 그대로 가지고 있음

3. 미약한 자료형의 검사기능, 미약한 배열에서 첨자의 범위 검사기능

 

C언어 컴파일러

1. IDE 제공 컴파일러 

 - IDE = Integrated Development Environments, 통합 개발 환경

 - 프로그램 개발에 관련된 모든 작업을 하나의 프로그램 안에서 처리되는 환경을 제공하는 소프트웨어

 - 컴파일러 내장

 - 따로 Command를 입력할 필요 없이 단축키를 사용해서 자동으로 컴파일

2. Command line Compiler

 - 직접 Command를 입력해 소스파일을 실행파일로 변환해야 함

 - GCC (GNU에서 제작한 Command line compiler) 

 

 

접근자 (accessor) : 멤버 변수 값을 반환하는 멤버 함수

설정자 (mutator) : 멤버 변수 값을 변경하는 멤버 함수

 

접근자와 설정자

- 일반적으로 get이나 set이 멤버함수의 이름 앞에 붙여짐

   ex. getSpeed(), setSpeed()

- 사용 이유

   (1) 정보 은닉

        클래스의 인터페이스와 구현을 분리하는 것이 좋은데, 이 이유는 구현을 변경하기 쉬워지기 때문

 

        ex) gear 변수를 advanced_gear 변수로 변경한다고 가정
        만약 외부에서 gear멤버 변수를 직접 사용했다면 gear멤버 변수의 이름 마음대로 변경 불가능
        하지만, 접근자와 설정자 사용시 변경 편리

//변경 전
int getGear(){
	return gear;
}
void setGear(ing g){
	gear=g;
}

//변경 후
int getGear(){
	return advanced_gear;
}
void setGear(ing g){
	advanced_gear=g;
}

 

 

    (2) 새로운 값이 적절한지 판단 가능

         설정자에서 매개변수를 통하여 잘못된 값이 넘어오는 경우, 사전에 차단 가능

 

         ex) 시간의 값을 25시로 변경하는 시도 거부

void setSpeed(int s){
	if(s<0) speed=0;
	else	speed=s;
}

 

    (3) 멤버 변수 값을 필요할 때마다 계산하여 반환 가능

 

         ex) 자동차의 속도를 바퀴의 회전 수와 바퀴의 반지름을 이용하여 매번 계산하여 반환

int getSpeed(){
	return (int)(rpm*2.0*3.14*wheel_radius);
}

 

    (4) 접근자만 제공 시

         - 자동적으로 읽기만 가능한 멤버 변수 생성 가능

         -  외부 코드가 실제 데이터 표현 방식을 모르게 할 수 있음

            (접근자: 반환하는 데이터의 형식 제어 가능)

 

동적으로 객체 생성 - new 사용

객체에 대한 포인터 사용하여 객체 사용

명시적으로 객체 삭제 - delete 사용

 

Car *dynCar = new Car;	//동적 객체 생성
dynCar -> speed = 100;	//동적 객체 사용
delete dynCar;		//동적 객체 삭제

 

<예시>

#include <iostream>
#include <string>
using namespace std;

class Car {
public: 
	//멤버 변수 선언
	int speed; //속도
	int gear;	//기어
	string color;	//색상

	//멤버 함수 선언
	void speedUp() {	//속도 증가 멤버 함수
		speed += 10;
	}
	void speedDown() {	//속도 감소 멤버 함수
		speed -= 10;
	}
	void show() {	//상태 출력 멤버 함수
		cout << speed << endl;
		cout << gear << endl;
		cout << color << endl;
	}
};

int main() {
	// 객체 동적 생성
	Car *dynCar = new Car;

	//동적 객체 사용
	dynCar->speed = 100;
	dynCar->gear = 2;
	dynCar->color = "green";
	dynCar->speedUp();
	dynCar->speedDown();
	dynCar->show();

	//객체 동적 삭제
	delete dynCar;

	return 0;
}

 

동적으로 객체를 생성하는 이유에 대해 궁금증이 생겼다. (책에 나오지 않아 구글 검색을 이용)

 

동적으로 객체를 생성하는 경우와 아닌 경우의 차이 : 메모리 영역의 차이

동적으로 객체를 생성할 경우 - 힙 영역

동적으로 객체를 생성하지 않을 경우 - 스택 영역

 

스택 영역 

- 함수내에 정의된 지역 변수가 저장되는 영역(즉, 일반적인 변수가 올라가는 영역)

    cf) 함수는 LIFO(Last In First Out) 형태의 스택 구조를 갖고 있음

- 범위를 벗어날 경우 메모리 자동으로 해제

 

힙 영역 

- 동적할당을 통해 생성된 동적 변수를 관리하기 위한 영역 (동적 변수 : new를 통해 생성되는 변수)

- 직접 해제하기 전까지는 메모리에 유지됨

 

스택 영역의 경우, 컴파일러가 미리 공간을 예측할 수 있기 때문에 함수에서 잠깐 쓰고 자동으로 해제 시키기 위해서는 스택 영역을 사용하는 것이 좋음

동적 변수의 경우 어느정도 할당 될 지 예측할 수 없기 때문에 runtime(즉 프로그램 실행중)에 결정됨. 따라서 프로그램 내에서 해당 변수를 계속 사용하기 위해서는 힙 영역을 사용하는 것이 좋음

 

함수가 외부로부터 매개 변수를 통하여 데이터를 받는 방법(함수 호출 시 인수 전달 방식)

(1) 값에 의한 호출(call by value)

(2) 참조에 의한 호출(call by reference)

 

값에 의한 호출 (= 복사본 전달)

"복사본 전달"인 이유: 복사본을 아무리 바꿔도 원본이 바뀌지 않음

 

#include <iostream>
using namespace std;

void swap(int x, int y);

int main() {
	int a = 100, b = 200;
	cout << "swap 호출 전 (a,b) : (" << a << "," << b << ")" << endl;	//(100,200)

	swap(a, b);
	cout << "swap 호출 후 (a,b) : (" << a << "," << b << ")" << endl;	//(100,200)

	return 0;
}

void swap(int x, int y) {
	int tmp;
	tmp = x;
	x = y;
	y = tmp;

}

 

위의 코드를 보면

호출 전과 호출 후의 a, b값이 동일하게 나옴

- 함수로 변수의 값만 전달되기때문에 원본 변수 자체를 변경할 수 없음

 

참조에 의한 호출

- 전역변수를 사용하지 않고 함수 외부의 변수들을 참조하여 변경 가능하기 때문에 사용

 

참조에 의한 호출 사용 방법

(1) pointer(포인터) 사용

(2) reference(참조자) 사용

 

참조에 의한 호출 - pointer 

- 함수가 포인터를 통하여 변수의 주소를 받을 경우, 함수는 그 주소에 위치한 변수의 값 변경 가능

#include <iostream>
using namespace std;

void swap(int* px, int* py);

int main() {
	int a = 100, b = 200;
	cout << "swap 호출 전 (a,b) : (" << a << "," << b << ")" << endl;	//(100,200)

	swap(&a, &b);
	cout << "swap 호출 후 (a,b) : (" << a << "," << b << ")" << endl;	//(200,100)

	return 0;
}

void swap(int* px, int* py) {
	int tmp;
	tmp = *px;
	*px = *py;
	*py = tmp;

}

 

- 함수 호출시 인수가 a,b가 아닌 &a,&b 이어야함(값이 아닌 변수의 주소 전달)

 

참조에 의한 호출 - reference

- 함수의 매개변수를 참조자로 선언하게 되면 호출된 함수에서는 이 참조자를 이용하여 원본 변수의 값 수정할 수 있음

#include <iostream>
using namespace std;

void swap(int &rx, int &ry);

int main() {
	int a = 100, b = 200;
	cout << "swap 호출 전 (a,b) : (" << a << "," << b << ")" << endl;

	swap(a, b);
	cout << "swap 호출 후 (a,b) : (" << a << "," << b << ")" << endl;

	return 0;
}

void swap(int &rx, int &ry) {
	int tmp;
	tmp = rx;
	rx = ry;
	ry = tmp;

}

 

- 위의 코드에서 swap( )함수의 정의를 보면, 매개변수 rx,ry가 참조자로 선언되어 있음

- main()에서 swap()를 호출할 때는 변수a,b가 swap()의 인수로 전달함

- 포인터보다 사용하기 편리함

 

참조자(reference) : 변수에 별명을 붙여 접근

- 변수 var 선언 후 ref라고 하는 별명 붙이기 (& 사용)

int var = 10;
int &ref = var;

// 참조자에 값을 대입하면 참조자가 참조하는 변수의 값이 변경됨
ref = 20; 	// var의 값이 20으로 변경됨

 

 

 

참조자 (reference) vs 포인터 (pointer)

 

1. 참조자는 선언과 동시에 초기화 되어야 함

int &ref;	// 컴파일 에러

 

2.  포인터는 변수이기 때문에 포인터가 가리키는 대상은 변경될 수 있음

    참조자는 자신만의 메모리 공간이 할당되지 않기 때문에 참조자가 가리키는 대상은 변경될 수 없음

int &ref = var1;
ref = var2;		//컴파일 에러 : 참조하는 대상을 변경할 수 없음

 

3. 참조자를 상수로 초기화 하면 역시 컴파일 에러남

참조자는 참조대상을 변경할 수 없음 -> 참조하는 대상이 수시로 변경되는 경우에는 포인터 사용

참조자는 선언과 동시에 반드시 초기화 되기 때문에 NULL이 될 수 X

 -> NULL이 될 가능성이 있는 경우에는 포인터 사용( 포인터의 경우에는 NULL 포인터가 존재함)

 

 

참조자의 용도 (상수 포인터와 가장 유사)

- 주로 함수 호출 시에 매개 변수와 반환 값으로 사용됨

- 참조자를 함수의 매개 변수로 사용하면 참조자를 이용하여 함수 외부에 존재하는 변수의 값을 변경할 수 있음

#include <iostream>
using namespace std;

void DecByR(int &r) {	//r은 time의 참조자
	r--;
	return;
}

void DecByP(int* p) {
	--(*p);
	return;
}

int main() {
	int time = 10;

	DecByR(time);	//time을 전달
	cout << time << endl;	// 9

	DecByP(&time);	//time의 주소를 전달
	cout << time << endl;	// 8 

	return 0;
}

 

const 참조자

- 참조자 앞에도 const 수식어 사용 가능 

- 상수를 매개 변수로 받는 경우에 필요함

 

+ Recent posts