반응형
728x90
반응형

데이터를 csv 형식 및 json 형식으로 저장하는 예제이다.

1. 리눅스 리다이렉트 방식을 이용한 저장

1
2
3
4
5
6
7
8
9
10
11
12
 
# 리다이렉트 방식으로 csv 저장 방법.
 
# csv 의 Head 를 출력.
print('index,student-number,name')
 
# csv 의 Body 를 출력.
print('0,20111299,유승호')
print(','.join(['1','20111341','김김김']))
print(','.join(['2','24111341','싱상송']))
print(','.join(['3','32214545','오로치마루']))
print(','.join(['4','12313132','아오키지']))
cs

 

위와 같이 출력하는 코드를 작성한 후, 이를 실행할 때 리다이렉트 방법으로 csv로 저장한다. 아래는 그 방법과 실행 결과이다.

2. csv 파이썬 모듈을 이용한 저장.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
# csv 모듈 방식으로 csv 저장 방법.
 
import csv
 
with open('csv-module.csv''w', newline=''as f:
    writer = csv.writer(f)
    writer.writerow(['index','student-number','name'])
    writer.writerows([
        [020111299'유승호'],
        [120111341'김김김'],
        [224111341'싱상송'],
        [332214545'오로치마루'],
        [412313132'아오키지'],
    ])
 
 
cs

 

 

3. json 형식으로 저장

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
# json 저장 방법.
 
import json
 
# json 으로 저장할 데이터들을 list와 dict 형식으로 저장한다.
student_info = [
    {'index'0'student-number'20111299'name''유승호'},
    {'index'1'student-number'20111341'name''김김김'},
    {'index'2'student-number'24111341'name''싱상송'},
    {'index'3'student-number'32214545'name''오로치마루'},
    {'index'4'student-number'12313132'name''아오키지'}
]
 
# 출력
# print(json.dumps(student_info, ensure_ascii=False, indent=2))
 
# 파일 출력
with open('save-json.json','w'as f:
    json.dump(student_info, f)
 
cs

16 라인에서 ensure_ascii 를 False 값을 주게 되면 띄어쓰기를 넣게 되고, indent를 넣으면 들여쓰기를 한다.

다음은 그 결과이다.

 

728x90
반응형
728x90
반응형

xml etree를 이용하여 rss 에서 원하는 정보를 추출하는 예제이다.

기상청에서 제공하는 날씨 데이터 rss를 첨부 파일에 저장했다.

rss.xml
0.09MB

---

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from xml.etree import ElementTree # XML Parser
 
# parse 함수로 읽고 분석 후, ElementTree 객체 생성
tree = ElementTree.parse('./rss.xml')
# 해당 트리의 root 요소 반환
root = tree.getroot()
# 해당 경로에 해당하는 요소들의 갯수를 출력
print(len(root.findall('channel/item/description/body/location')))
# 추출
for loc in root.findall('channel/item/description/body/location'):
    print('지역 [{}] 의 기상청 소식입니다 -------------------'.format(loc.find('city').text))
    for data in loc.findall('data'):
        tm_ef = data.find('tmEf').text
        tmn = data.find('tmn').text
        tmx = data.find('tmx').text
        wf = data.find('wf').text
 
        print(tm_ef, tmn, tmx, wf)
cs

위 코드에 대한 결과이다.

728x90
반응형
728x90
반응형

기본 내장된 url library를 이용하여 간단하게 웹 코드 및 헤더 정보, 상태 코드 읽어오는 예제이다.

------

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from urllib.request import urlopen
import sys
 
= urlopen('http://example.com')
 
# <class 'http.client.HTTPResponse'>
print("urlopen의 반환 타입은 : ", type(f))
 
# 소스 코드의 출력
print("f.read() 의 출력은? --- --- --- --- Source Code ")
print(f.read())
 
# 각종 헤더 정보 출력
print("f.getHeader() 의 출력은? --- --- --- --- ")
header_info = f.getheaders();
for info in header_info:
    print(info)
 
# 상태 코드 출력
print("f.status 의 출력은? --- --- --- ---")
print(f.status)
 
 
cs

 

아래는 그 결과이다. 

728x90
반응형
728x90
반응형

오늘은 파이썬 공부하면서 필요했던 과정인 파이썬 설치 및 가상 환경 세팅 방법에 대해서 포스팅한다. 굉장히 간단하다 ㅋ

그런데 파이썬3 설치는 그렇다 치더라도 파이썬 venv는 도대체 무엇인가? 짤막하게 정리해보겠다.

Venv는 Virtual Environment, 즉 가상 환경을 의미한다. 이해하기 쉽게 비유를 해보자면, 물리적인 하나의 큰 시스템 공간을 논리적으로 나누어서

여기부터 여기는 철수 공간으로 해~,
그리고 여기부터 여기는 영희 공간으로 해~
그리고 각자 그 공간 속에서만 행동을 하려무나~ 

좀 더 자세히 그림으로 설명해보겠다. 먼저 기본 전제이다.

철수와 영희는 각각 파이썬으로 이루어진 프로그램 A와 프로그램 B를 실행하려고 한다. 그런데 이 프로그램 A와 B는 a라는 파이썬의 패키지를 사용하지만, 각자 원하는 버전이 다른 것이다. 버전이 다르면 실행이 불가하다는 전제를 둔다. 그런데 철수는 컴퓨터 수업의 오전 반, 영희는 컴퓨터 수업의 오후 반인데 안타깝게도 자리마저 동일한 자리라서 같은 컴퓨터를 사용한다.

이러한 전제와 상황 속에서 가상 환경을 사용하지 않을 경우 어떻게 될까?

철수와 영희는 매일 싸울 것이다. 매 오전/오후 수업마다 서로의 a 패키지를 계속해서 설치했다가 지웠다가를 반복하기 때문이다. 그렇다면 가상 환경을 사용하게 되면 어떻게 될까?

꿀이다. 싸울 필요가 없다. 하나의 공간을 논리적으로 나누어서 철수의 영역, 영희의 영역 서로 다른 버전의 a 패키지를 따로 따로 설치하여 실행도 따로따로 한다. 이 때 실행할 때에는 가상 환경을 사용하지 않을 때와 다르게 약간의 조치가 필요하겠지만 (빨간 ㄱ 표시) 매일 지우고 깔고 싸우고를 반복하는 행위에 비하면 아무 문제가 되지 않는다.

이것이 가상 환경의 개념이며 비유이다.

그렇다면 이번엔 python3 설치 방법과 python3 venv 설치 방법 및 활성화 / 비활성화 방법을 포스팅할 것이다.

1. Python3 설치

sudo apt install python3

이게 끝이다. 겁나 간단하다 ㅋ

2. Python3-venv 설치

sudo apt install python3-venv

이것도 이렇게 끝이다ㅋ 겁나 간단하다ㅋㅋ

3. 가상 환경 세팅

python3 -m venv scrap(가상 공간 이름)

이렇게 간단하다 ㅋㅋ이런거 가지고 포스팅하는 것 조차 민망할 정도다 ㅋ

세팅이 잘 되는지를 확인하기 위해 생성된 가상 공간 이름의 디렉토리로 접근했을 때, 위와 같은 바이너리, 헤더, 라이브러리 등이 존재하면 세팅이 잘 진행된 것이다.

4. 가상 환경 활성화

source 가상 환경 경로/bin/activate

마찬가지다. 이렇게 간단하다. 다만, 활성화가 제대로 되었는지 확인할 때에는 생성한 가상 환경의 이름으로 프롬프트 앞쪽에 뜬다. (사진 왼쪽 하단)

scrap 가상 환경 상태에서 패키지를 설치한다고 하더라도 다른 명의(?)의 가상 환경이나 실제 오리지널 환경(가상 환경 상태가 아닌 오리지널)에서는 설치되어있지 않다. 즉, 가상 환경은 다른 환경에 영향을 끼치지 않는 독립적인 공간이자 시스템이란 것이다. 끝

728x90
반응형
728x90
반응형

Map은 연관 컨테이너에 속하는 컨테이너의 한 종류이다. 파이썬의 Dictionary 사전과 같은 자료구조를 갖는다.

Map은 사전처럼 Key(단어)를 갖고, 그 Key에 해당하는 Value(뜻)를 갖는다. 왼쪽 그림처럼 Apple이라는 단어를 찾으면 사과라는 뜻이 나오 듯, key 값을 넣으면 value 값이 나오는 형태이다.

Map에 자료를 추가하거나, 자료를 찾기 위해서는 insert(), find() 등의 함수를 사용하지만 Map의 특성으로 인해서 추가와 탐색을 한 형태로 나타낼 수 있다.

  my_map["apple"] = "핸드폰"; my_map["apple"];
"apple" key가 my_map내에 있을 경우
(value = "사과")
(1) "핸드폰" 값으로 대입 갱신. (2) "사과"를 반환
"apple" key가 my_map내에 없을 경우 (3) key - apple / value - 핸드폰으로
map 컨테이너에 추가 됨.
(4) 반환되는 값이 없다.

첫 번째, 기존의 동일한 key가 map에 존재하는데, 동일한 key로 다시 value 값을 등록하는 경우는 갱신된다.
두 번째, 기존의 동일한 key가 map에 존재한다면, 기존의 key값에 해당하는 value 값을 반환시킬 수 있다.
세 번째, key가 map에 존재하지 않는데, key로 value 값을 등록하는 경우 map에 새롭게 추가된다.
네 번째, key가 map에 존재하지 않는다면, key 자체도 없고 그에 따라서 value도 없으므로 반환되는 값이 없다.

간단한 예제로 마무리 지을 것이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// https://colorscripter.com/
#include <iostream>
#include <string>
#include <map>
 
using namespace std;
 
int main(void)
{
    map<stringstring> my_map; // key에 해당하는 string, value에 해당하는 string
 
    my_map["a"= "apple";
    my_map["b"= "banana";
    my_map["c"= "carrot";
 
    cout << "--- key로 접근하여 value을 출력하기. " << endl;
    cout << my_map["a"<< endl;
    cout << my_map["b"<< endl;
    cout << my_map["c"<< endl;
 
    cout << "--- iterator 이용하여 key와 value 출력하기. " << endl;
    map<stringstring>::iterator it;
    for (it = my_map.begin(); it != my_map.end(); it++)
        cout << it->first << " : " << it->second << endl;
 
    return 0;
}
 
cs

10번 라인과 같이 key 값의 자료형과, value 값의 자료형들을 명시해야한다. 또한 22번 라인에도 또한 동일한 자료형을 명시하여 iterator 선언해야한다.

24번 라인에서 map내의 iterator 클래스의 멤버 first와 second는 각각 key와 value를 나타낸다.

map을 공부하다보니 pair 및 multimap도 관련이 생기고, tuple도 정리해야겠다는 생각이 들었다.

다음 시간에 정리해보자.

728x90
반응형

'프로그래밍응용 > Modern & STL' 카테고리의 다른 글

Tuple  (0) 2021.01.03
Pair  (0) 2021.01.03
Set  (0) 2020.09.15
List  (0) 2020.09.14
Deque  (0) 2020.09.13
728x90
반응형

 

Set 컨테이너에 대해서 공부해보았다. Set은 연관 컨테이너 중 하나이다. 다음은 연관 컨테이너의 특성이다.

  • 원소들을 검색하기 위한 키(key)를 가지고 있다. (키와 값의 쌍 형태로 저장되는 컨테이너도 있다)
  • 자료들은 정렬되어 있다. (하지만 순서는 의미가 없다)
  • 삽입되는 요소의 위치를 지정할 수 없다.
  • Tree 구조를 기반으로 동작한다.

Set 컨테이너는 '집합'이다. 

중학교 때 배우는 집합의 특징에 대해서 생각해 볼 수 있다.

  • 중복이 허용되지 않는다.
  • 순서가 상관이 없다.

Set이라는 컨테이너는 집합의 특징을 그대로 갖는다. 그리고 이 집합 내에 저장되는 요소를 키(key)라고 한다.

그러나 중복이 허용되는 집합 컨테이너가 존재한다. 다중 집합인 multi-set이다.
중복이 허용되는 것을 제외하면 set과 똑같다. 

간단한 컨테이너 개념이기 때문에 코드로 바로 정리한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// https://colorscripter.com/
#include <iostream>
#include <set>
 
using namespace std;
 
template <typename T>
void print_list(const T& c);
 
int main(void)
{
    set<int> my_set;
    multiset<int> my_multiset;
 
    set<int>::iterator set_it;
    multiset<int>::iterator multiset_it;
 
    cout << "set에서의 요소 추가" << endl;
    my_set.insert(6);
    my_set.insert(7);
    my_set.insert(8);
    my_set.insert(8); // 중복 값이기 때문에 insert가 이루어지지 않음.
    print_list(my_set);
 
    cout << "multi set에서의 요소 추가" << endl;
    my_multiset.insert(100);
    my_multiset.insert(100); // 중복 값 허용이므로 insert가 이루어진다.
    my_multiset.insert(my_set.begin(), my_set.end());
    print_list(my_multiset);
 
    cout << "set에서의 요소 탐색" << endl;
    set_it = my_set.find(8);
    if (set_it != my_set.end())
        cout << *set_it << " 가 발견됨." << endl;
 
    cout << "multi set에서의 요소 탐색" << endl;
    multiset_it = my_multiset.find(100);
    if (multiset_it != my_multiset.end())
        cout << *multiset_it << " 가 발견됨." << endl;
 
    cout << "set에서의 요소 삭제(6)" << endl;
    my_set.erase(6); 
    print_list(my_set);
 
    cout << "multi set에서의 요소 삭제(100)" << endl;
    my_multiset.erase(100); // 100 요소가 여럿인 경우 모두 삭제
    print_list(my_multiset);
 
    return 0;
}
 
 
template <typename T>
void print_list(const T& c)
{
    typename T::iterator it;
    // typename을 붙이는 이유 : 
    // 붙이지 않을 경우 T::iterator에서 iterator을 T 클래스 내의 변수로 생각하기 때문에 T::iterator 자체가 type이라는 것을 명시해야함.
    for (it = c.begin(); it != c.end(); it++)
        cout << "iterator value : " << *it << endl;
    return;
}
cs

먼저, 21, 22번 라인처럼 set 컨테이너에 같은 값을 키로 등록하려고 하는 경우, 나중에 추가되는 중복 값은 추가되지 않고 무시된다. 내부적으로 조건에 의하여 처리된다.

반면, 26, 27번 라인처럼 multiset 컨테이너에서는 중복 값 추가가 허용된다.

46번 라인처럼 multiset컨테이너에서 중복되는 값을 삭제한다면 중복되는 값들 모두 사라진다. 예를 들어 100이 두개 들어있는 multiset의 경우에서 erase(100)을 실행하면 100 두 개가 모두 사라진다.

728x90
반응형

'프로그래밍응용 > Modern & STL' 카테고리의 다른 글

Pair  (0) 2021.01.03
Map  (0) 2020.09.15
List  (0) 2020.09.14
Deque  (0) 2020.09.13
모든 컨테이너 공통 멤버  (0) 2020.09.13
728x90
반응형

오늘은 지난 번 Deque 정리에 이어서 List 정리를 해본다.

LIST 란?

리스트는 벡터와 디큐와 마찬가지로 순차 선형 콘테이너이다. 그래서 외부에서 볼 때에는 벡터와 완전히 동일한 듯 보이지만, 구조 자체부터 크게 다르다.

벡터는 순차 배열 형태였다면, 리스트는 이중 연결 리스트로 구현된다. 다음 그림과 같이 말이다.

위와 같은 이중 연결 리스트로 구현되어 있기 때문에 벡터에서의 순회 방법에서 아주 조금의 차이가 있다. begin() 부터 end() 까지 주소 값 비교를 통한 순회가 의미가 없기 때문이다. 무조건 노드의 링크를 타고 가는 방식의 포인터 연산으로 접근해야한다. ( 이는 연산자들이 오버로딩되어 자동으로 포인터 연산 되도록 구현되어 있음.)

또한 링크드 리스트로 구현되어 있기 때문에 인덱스가 없다. 그렇단 소리는 임의 접근이 불가능하다는 소리이고, 탐색을 할 때는 모든 노드를 링크를 타고 순회해야한다.

다만, 삽입이나 삭제를 할 때, 벡터에서는 요소들의 인덱스 재 조정 그리고 추가 메모리 공간 확장 및 복사/확장이 필요하지만 리스트에서는 링크를 변경하면 되므로 삽입/삭제 시에는 속도가 빠르다는 장점이 있다.

결국, 중간에서의 삽입 및 삭제가 빈번한 경우 사용하면 적합할 것 같다.

s

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <iostream>
#include <list>
 
using namespace std;
 
void print_list(list<int>& l)
{
    list<int>::iterator list_it;
    for (list_it = l.begin(); list_it != l.end(); list_it++// 링크드리스트이기 때문에 <, > 연산이 의미가 없다.
        cout << "list iterator value : " << *list_it << endl;
    return;
}
bool cond(int n) // 기본 조건에 의한 삭제를 위한 함수.
{
    return n > 901;
}
bool desc(int a, int b) // sort의 내림차순을 위함.
{
    return a > b;
}
 
int main(void)
{
    list<int> my_list;
    list<int> new_list;
 
    cout << "push_front, push_back 함수 호출 --- --- ---" << endl;
    my_list.push_back(100);
    my_list.push_back(200);
    my_list.push_front(900);
    print_list(my_list); // 900 100 200
    
    cout << "insert 함수 호출 --- --- ---" << endl;
    my_list.insert(--(my_list.end()), 999); 
    print_list(my_list); // 900 100 999 200
 
    cout << "remove & remove_if 함수 호출 --- --- ---" << endl;
    my_list.remove_if(cond); // 901 제거
    my_list.remove(100); // 100 제거
    print_list(my_list); // 900 200
 
    cout << "reverse 함수 호출 --- --- ---" << endl// 원소들을 뒤집어서 나열
    my_list.reverse();
    print_list(my_list); // 200 900
 
    cout << "sort 함수 호출 오름차순 --- --- ---" << endl;
    my_list.sort();
    print_list(my_list); // 200 900
 
    cout << "sort 함수 호출 내림차순 --- --- ---" << endl// 식을 함수 형태로 주어 내림차순 구현
    my_list.sort(desc);
    print_list(my_list); // 200 900
 
    cout << "unique 함수 호출 --- --- --- " << endl// 인접한 데이터 중에 중복되는 요소들을 제거한다.(연속적으로 나오는 중복을 허용 X)
    new_list.insert(new_list.begin(), 55);
    new_list.insert(new_list.begin(), 33);
    new_list.insert(new_list.begin(), 55);
    new_list.insert(new_list.begin(), 55);
    new_list.unique();
    print_list(new_list); // 실행결과 : 55 33 55
 
    cout << "merge 함수 호출 --- --- --- " << endl;
    new_list.sort();
    my_list.sort(); // 각각의 리스트들은 꼭 정렬되어 있어야 한다.
 
    new_list.merge(my_list); // 복사(copy)하는 것이 아니라 요소의 이동(move)이다.
    print_list(new_list); // 실행결과 : 33 55 55 200 900
    print_list(my_list); // 실행결과 : 비어 있음 -> 이동했기 때문에
 
    cout << "splice 함수 호출 --- --- --- " << endl;
    my_list.push_front(300);
    my_list.push_front(100);
    my_list.splice(my_list.begin(), new_list); // 복사(copy)하는 것이 아니라 요소의 이동(move)이다.
    print_list(new_list); // 실행결과 : 비어 있음 -> 이동했기 때문에
    print_list(my_list); // 실행결과 :  33 55 55 200 900 100 300
 
    return 0;
}
cs

s간단한 설명을 붙이자면,

34번 라인처럼 insert시, 임의 접근이 불가능하므로 포인터 연산(오버로딩된)을 통해 위치를 명시한다.
그리고 remove_if 함수를 통해 조건부 삭제가 가능한데, 이 때 조건은 13번 라인의 bool 반환 타입의 함수 형태로 기입한다. 함수의 이름을 적으면 된다. 

50번 라인에서 sort 함수를 통해 기본적인 오름차순 정렬이 가능한데, 내림차순이나 다른 형태의 정렬을 위해선 remove_if 처럼 조건을 전달해야한다. 17번 라인의 함수 이름을 전달하면 된다.

59번 라인의 unique 함수는 인접한 데이터 중에 중복 요소가 있으면 중복을 제거한다. 내가 가만히 보니, 11/11/22/22 는 11/22 로 중복을 제거하지만 11/22/11/22인 경우는 중복이 제거가 되지 않는다... 참으로 이상하다

62번 라인과 70번 라인의 merge와 splice는 병합의 기능을 하는데, 참으로 불편한게 이 두 함수를 사용하기 위해서는 병합할 두 요소들이 모두 일정한 방법으로 정렬이 되어 있어야 한다는 점이다. 참으로 딱하구나... 또한 병합할 때에는 요소들 간의 복사가 이루어지는게 아니라 잘라내기&붙혀넣기 즉, 요소의 이동이 이루어지기 때문에 병합하는 쪽은 merge() 및 splice() 함수 호출 후에는 텅 비어있다.. 그런데 이것은 뭐 당연하다고 생각된다. 링크를 바꾸는 것이기 때문에!

이상 list^^

 

728x90
반응형

'프로그래밍응용 > Modern & STL' 카테고리의 다른 글

Map  (0) 2020.09.15
Set  (0) 2020.09.15
Deque  (0) 2020.09.13
모든 컨테이너 공통 멤버  (0) 2020.09.13
Iterator( With vector )  (0) 2020.09.13
728x90
반응형

Deque에 대한 정리 글이다.

STL Container의 한 요소인 Deque에 대해서 공부를 해보았고, 내용을 정리해보았다.

먼저, Deque(디큐? 데크?), 아무튼 이 Deque란 무엇일까? 생각을 해본다. 큐는 큐인데 반대인, 그래서 디(부정) 큐 라고 하는 것인가?

그래서 찾아보았다.

Deque 란?

벡터와 아주 유사한 동적 배열로, 배열의 전단과 후단에서 모두 요소를 추가하고 삭제하는 것을 허용한다라는 점이 벡터와의 차이점이다. 그 외에는 말 그대로 동적 배열이다.

매우 간단하니, 매우 간단한 예제를 들겠다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
deque<int> dq;
deque<int>::iterator d_it;
 
dq.push_back(300);
dq.push_back(400);
dq.push_front(200);
dq.push_front(100);
 
cout << "인덱스를 이용한 출력" << endl;
for (int i = 0; i < dq.size(); i++)
    cout << "dq[" << i << "] : " << dq[i] << endl;
    
cout << "반복자를 이용한 출력" << endl;
for(d_it=dq.begin(); d_it<dq.end();d_it++)
    cout << "*d_it : " << *d_it << endl;
cs

 

위 코드, 실행결과, 그림이 모든 설명을 다 해줬다.

 

728x90
반응형

'프로그래밍응용 > Modern & STL' 카테고리의 다른 글

Set  (0) 2020.09.15
List  (0) 2020.09.14
모든 컨테이너 공통 멤버  (0) 2020.09.13
Iterator( With vector )  (0) 2020.09.13
Vector  (0) 2020.09.12
728x90
반응형

이번엔 모든 컨테이너에서 공통적으로 지니는 멤버 함수들을 정리해 볼 것이다.

Container 대신에 해당하는 컨테이너 및 자료형 타입을 기입하여 사용하면 된다.

생성자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    vector<int> v1; // 1. Container(), 컨테이너를 생성.
    vector<int> v2(10); // 2. Container(size), 길이가 10개인(10*sizeof(type)) 컨테이너 생성.
    vector<int> v3(105); // 3. Container(size, value),  값이 5로 전부 채워진 길이 10개 컨테이너 생성.
    vector<int> v4(v3.begin(), v3.begin()+4); // 4. Container(iterator, iterator),  v3의 값을 복사하며 생성.
 
    vector<int>::iterator it;
 
    cout << endl << "v2---" << endl;
    for (it = v2.begin(); it < v2.end(); it++)
        cout << *it << ", ";
 
    cout << endl << "v3---" << endl;
    for (it = v3.begin(); it < v3.end(); it++)
        cout << *it << ", ";
 
    cout << endl << "v4---" << endl;
    for (it = v4.begin(); it < v4.end(); it++)
        cout << *it << ", ";
cs

실행 결과

empty()와 clear() 

1
2
3
4
5
6
7
8
9
10
11
12
vector<int> v1; 
vector<int> v2(10); 
vector<int> v3(105); 
vector<int> v4(v3.begin(), v3.begin()+4); 
 
vector<int>::iterator it;
 
cout << "vector<int> v1; : " << v1.empty() << endl// true 반환
cout << "vector<int> v2(10); : " << v2.empty() << endl// false 반환
cout << "vector<int> v3(10, 5); : " << v3.empty() << endl// false 반환
v4.clear(); // 모든 요소 제거
cout << "v4.clear(); : " << v4.empty() << endl// true 반환
cs

empty() 멤버 함수는 해당 콘테이너가 비어져있는지를 확인하는 함수이고, clear() 멤버 함수는 해당 콘테이너 속 요소를 모두 제거 한다.

begin(), end() 와 erase()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
vector<int> v1; 
vector<int> v2(10); 
vector<int> v3(105); 
vector<int> v4(v3.begin(), v3.begin()+4); 
 
vector<int>::iterator it;
 
v3.erase(v3.begin(), v3.end() - 1); // 범위로 지우기 : v3.begin() 부터 (v3.end()-1)-1 까지 지운다.
for (it = v3.begin(); it < v3.end(); it++)
    cout << *it << ", ";
cout << endl;
 
v3.erase(v3.begin()); // 위에서 하나 남기고 모두 지웠으니, 시작 하나만 지우면 다 지워지는 꼴.
for (it = v3.begin(); it < v3.end(); it++)
    cout << *it << ", ";
cout << endl;
cs

begin() 함수와 end() 함수는 콘테이너의 시작과 끝 위치를 iterator 형으로 리턴한다. erase 멤버 함수는 컨테이너 내의 요소를 지우는 함수인데, 8번 라인처럼 범위로 지울 수 있고, 13번 라인처럼 해당 요소에 대해서 지울 수 있다.

insert()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
vector<int> v3(105); 
vector<int> v4(5100); 
vector<int>::iterator it;
 
v3.insert(v3.end() - 19999);
 
for (it = v3.begin(); it < v3.end(); it++)
    cout << *it << ", ";
cout << endl;
 
v4.insert(v4.end(), v3.begin(), v3.end());
 
for (it = v4.begin(); it < v4.end(); it++)
    cout << *it << ", ";
cout << endl;
cs

 

insert() 멤버 함수는 요소를 삽입하는 함수인데 마찬가지로, 5번 라인/11번 라인의 두 가지 형태로 삽입이 가능하다. 요소를 삽입하느냐, 범위로 삽입하느냐.

push_back(), pop_back()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
vector<int> v3(105); 
vector<int> v4(5100); 
 
vector<int>::iterator it;
 
v3.push_back(1000000);
for (it = v3.begin(); it < v3.end(); it++)
    cout << *it << ", ";
cout << endl;
 
v3.pop_back(); // 리턴 값이 없으며, 삭제만 가능하다.
for (it = v3.begin(); it < v3.end(); it++)
    cout << *it << ", ";
cout << endl;
cs

push_back 함수는 벡터의 가장 마지막에 요소를 추가, pop_back() 함수는 가장 마지막 요소를 삭제한다. 11번 라인에서의 주석처럼 pop_back()는 리턴 값이 없고 삭제만 가능하다.

operator=(),  operator()==, size()


1
2
3
4
5
6
7
8
9
10
11
12
vector<int> v1({ 1,2,3,4,5 });
vector<int> v2;
 
cout << "v1.size() : " << v1.size() << endl;
v2 = v1; // operator()=
cout << "v2.size() : " << v2.size() << endl;
 
if (v1 == v2)
    cout << "v1과 v2는 동일한 값을 지닙니다." << endl;
else
    cout << "v1과 v2는 동일한 값을 지니지 않습니다." << endl;
    
cs

 

이로써 공통 멤버함수들에 대한 정리 끝!

728x90
반응형

'프로그래밍응용 > Modern & STL' 카테고리의 다른 글

List  (0) 2020.09.14
Deque  (0) 2020.09.13
Iterator( With vector )  (0) 2020.09.13
Vector  (0) 2020.09.12
STL:Container, Iterator, Algorithm 개념  (0) 2020.09.10
728x90
반응형

반복자(iterator) 에 대한 정리이다. 

반복자는 컨테이너의 요소를 가리키는 객체이다. 포인터와 비슷한 개념이지만 일반화된 포인터라고 보면 될 것 같다. 이 반복자를 통해 컨테이너의 요소에 쉽게 접근할 수 있다.

그러니까 쉽게 말하자면 컨테이너는 여러 종류이지만 각 컨테이너들의 자료 구조나 코드적인 구조를 생각하지 않더라도 컨테이너의 요소들에 쉽게 접근할 수 있도록 만들어진 인터페이스와 같다.

나는 이 반복자가 따로 클래스 정의되어 있는 것인줄 알았다. 그런 것이 아니고 보니까 각각 컨테이너마다 반복자가 들어있던 것이다.

사용법은 정말 간단한 코드로 정리를 해놓는다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <vector>
using namespace std;
int main(void)
{
    int max_number = 0;
    int val = 0;
    vector<int> num_vector;
    vector<int>::iterator it; // 반복자를 선언한다.
 
    while (true)
    {
        cout << "벡터에 추가할 숫자를 입력하세요 (-123123 입력 시 종료) : ";
        cin >> val;
        if (val == -123123)
            break;
        else
            num_vector.push_back(val);
    }
    max_number = num_vector[0];
    for (it=num_vector.begin() ; it<num_vector.end(); it++
    {
        if (*it > max_number)
            max_number = *it;
    }
 
    cout << " 입력한 값 중에서 최대 값은 " << max_number << " 입니다." << endl;
    return 0;
}
cs

이전 코드와 다른 점은 컨테이너의 요소 순회를 정수 인덱스(i)가 아닌 반복자를 통해서 순회한다는 점인데, 9번 라인에서 벡터 콘테이너 클래스 템플릿 내에 존재하는 iterator를 선언하고, 21번 라인에서 선언한 반복자를 이용해서 시작과 끝을 설정하는 부분이다. 

위의 21번 라인에 있는 begin과 end 멤버는 어떤 반환을 하길래 저렇게 사용할까? 라는 생각에 벡터 컨테이너 클래스 내에서 begin과 end 멤버 함수의 정의를 확인해 보았는데, 친절하게도 아래와 같이 주석이 달려있다. 

반환형이 시퀀스의 시작을 위한 iterator 형태와 끝 iterator 형태를 반환하기 때문에 코드에서 선언한 반복자로 이를 반환 받은 후 범위에 대한 접근 처리를 진행할 수 있었던 것이다.

23, 24 라인과 같이 접근할 때에는 포인터를 사용하는 듯이 오버로딩된 연산자 * 을 통해서 진행된다.

728x90
반응형

'프로그래밍응용 > Modern & STL' 카테고리의 다른 글

Deque  (0) 2020.09.13
모든 컨테이너 공통 멤버  (0) 2020.09.13
Vector  (0) 2020.09.12
STL:Container, Iterator, Algorithm 개념  (0) 2020.09.10
C++ STL(Standard Template Library이란?  (0) 2020.09.07

+ Recent posts