본문 바로가기
Python

데이터 구조

by Salgoo26 2021. 8. 30.

[TOC]

데이터 구조

데이터 구조

  • 데이터에 편리하게 접근하고, 변경하기 위해 데이터를 저장하거나 조작하는 방법
  • 순서가 있는 데이터 구조
    • 문자열
    • 리스트
  • 순서가 없는 데이터 구조
    • 세트
    • 딕셔너리

문자열

  • 특징

    • 변경할 수 없고(immutable)
    • 순서가 있고(ordered)
    • 순회 가능함(iterable)
  # Immutable?
  a = 'my string'
  a[-1] = '!'

  => TypeError
  • 문자열 슬라이싱

    • 다음과 같이, 특정 문자열을 뒤집을 때 유용하게 사용 가능
  s = 'abcd'
  s[::-1]
  => dcba

문자열 관련 메서드

  • 문자열 조회/탐색

    • .find()

      • 문자열의 첫 번째 위치를 반환함
      • 없으면 -1을 반환
  # 형식
  str.find(x)

  # 예시
  'apple'.find('p')
  => 1

  'apple'.find('k')
  => -1
  • .index()

    • 문자열의 첫 번째 위치를 반환
    • 없으면 오류 발생
  ```python
# 형식
str.index(x)

# 예시
'apple'.index('p')
=> 1

'apple'.index('k')
=> ValueError
  ```
  • .replace()

    • 바꿀 대상의 글자를 새로운 글자로 바꿔서 반환
    • count를 지정하면, 해당 개수만큼만 진행
  ```python
# replace 메서드의 기본 형식
str.replace(old, new[, count])

# [, count] 가 무엇인지?
- optional elements 를 의미 (선택적 인자)
- 파이썬 문법이 아니라, 프로그래밍 언어를 문서상에서 잘 표현하기 위한 BNF 표기법

# 예시
'coo'.replace('o', '!')
=> 'c!!'

'wooo'.replace('o', '!', 2)
=> 'w!!o'
  ```
  • .strip()

    • 특정한 문자들을 지정하면 양쪽 제거(strip), 왼쪽 제거(lstrip), 오른쪽 제거(rstrip) 가능함
    • 인자값을 넣지 않으면 기본적으로 공백을 제거함
    • 인자값으로 문자열을 지정하면, 지정한 문자열을 제거
  ```python
# 형식
str.strip([chars])

# 예시
'  테스트     \n'.strip()
=> '테스트'

'  테스트   '.rstrip()
=> '  테스트'

'www.example.com'.strip('wcom')
=> '.example.'
  ```
  • .split()

    • 문자열을 특정한 단위로 나눠 리스트로 반환
  ```python
# 기본 형식
str.split(set=None, maxsplit = -1)

# 예시
'a,b,c'.split('_')
=> ['a,b,c']

'a b c'.split()
=> ['a', 'b', 'c']
  ```
  • .join()

    • 반복 가능한(iterable) 컨테이너의 요소들을 seperator(구분자)로 합쳐 문자열 반환
```python
# 기본 형식
'seperator'.join(iterable)

# 예시
'!'.join('green')
=> 'g!r!e!e!n'

' '.join(['3', '5'])
=> '3 5'
```
  • 문자열 변경

    • .capitalize()
      • 앞글자를 대문자로, 나머지는 소문자로
    • .title()
      • 공백 이후의 단어 첫 문자를 대문자로
    • .upper()
      • 모두 대문자로
    • .lower()
      • 모두 소문자로
    • .swapcase()
      • 반대의 경우(대-소)로 변경함
  • 문자열 검증 (True or False 반환)

    • .isalpha()

      • 알파벳 문자 여부
      • 단순 알파벳이 아는 유니코드 상의 letter (한글도 포함됨)
    • .isupper()

      • 대문자 여부
    • .islower()

      • 소문자 여부
    • .istitle()

      • 타이틀 형식 여부
    • .isdecimal(), .isdigit(), .isnumeric()


리스트

  • 특징
    • 변경 가능하고(mutable)
    • 순서가 있고(ordered)
    • 순회 가능함(iterable)

리스트 관련 메서드

  • 값 추가 및 삭제

    • .append()

      • 리스트의 끝에 값을 추가함
    • .extend()

      • 리스트에 iterable의 항목을 추가함
      • append() 와는 차이가 있다
      • 인자값이 iterable로서 들어가며, iterable의 요소들이 하나씩 추가됨
      #기본 형식
      list.extend(iterable)
      
      # 예시
      cafe = ['starbucks', 'tomntoms']
      cafe.extend(['hollys'])
      print(cafe)
      => ['starbucks', 'tomntoms', 'hollys']
      
      # 단순 문자열을 넣었을 때?
      cafe = ['starbucks', 'tomntoms']
      cafe.extend('hollys')
      print(cafe)
      => ['starbucks', 'tomntoms', 'h', 'o', 'l', 'l', 'y', 's']
    • .insert()

      • 정해진 위치 i에 값 x를 추가함
      • 범위를 넘어서는 인덱스 값을 인자로 넣으면, 에러가 나는 것이 아니라 맨 끝에 추가됨
      # 기본 형식
      list.insert(i, x)
      
      # 예시
      cafe = ['starbucks', 'tomntoms']
      cafe.insert(0, 'start')
      print(cafe)
      => ['start', 'starbucks', 'tomntoms']
      
      cafe.insert(100, 'end')
      print(cafe)
      => ['start', 'starbucks', 'tomntoms', 'end']
    • .remove()

      • 리스트에서 값이 x인 첫 번째 항목 삭제
      # 기본 형식
      list.remove(x)
      
      numbers = [1, 2, 3, 'hi']
      numbers.remove('hi')
      print(numbers)
      => [1, 2, 3]
    • .pop()

      • 정해진 위치 i에 있는 값을 삭제하고, 그 항목을 반환함
      • i값을 지정하지 않으면, 마지막 항목을 삭제하고 반환함
      # 형식
      list.pop(i)
      
      # 예시
      numbers = ['hi', 1, 2]
      re = numbers.pop()
      print(numbers)
      print(re)
      
      => ['hi', 1]
      => 2
    • .clear()

      • 리스트의 모든 항목을 삭제함
  • 탐색 및 정렬

    • .index()

      • 첫 번째 x값을 찾아 해당 index 값을 반환
      • 찾고자 하는 x 값이 리스트 내에 없을 경우 ValueError 발생
    • .count()

      • 리스트 내에 존재하는 특정 값의 개수를 반환함
      • 찾고자 하는 값이 리스트 내에 없다면 0을 반환
      # 예시
      numbers = [1, 2, 3, 1, 1]
      numbers.count(1)
      => 3
      
      numbers = [1, 2, 3, 1, 1]
      numbers.count(9)
      => 0
    • .sort()

      • 원본 리스트를 정렬함
      • None을 반환
      • sorted 함수와 차이점 존재 (sorted의 경우 원본을 정렬하지 않고, 정렬한 결과만 반환함)
      # 형식
      list.sort()
      
      # 예시
      numbers = [3, 2, 5, 1]
      result = numbers.sort()
      print(numbers, result)
      
      => [1, 2, 3, 5] None
      
      # sorted 함수의 예시
      numbers = [3, 2, 5, 1]
      result = sorted(numbers)
      print(numbers, result)
      
      => [3, 2, 5, 1] [1, 2, 5, 3]
    • .reverse()

      • 순서를 반대로 뒤집음
      • 정렬하는 것은 아님
      • sort()와 마찬가지로 원본을 변경하기 때문에, 반환값은 None
      # 형식
      list.reverse()
      
      # 예시
      numbers = [3, 2, 5, 1]
      result = numbers.reverse()
      print(numbers, result)
      
      => [1, 5, 2, 3] None

리스트 복사

  • 리스트의 복사는 같은 리스트의 주소를 참조함

  • 해당 주소의 일부 값을 변경하는 경우 이를 참조하는 모든 변수에 영향

  • 예시

    orgin_list = [1, 2, 3]
    copy_list = origin_list
    copy_list[0] = 999
    print(origin_list, copy_list)
    
    => [999, 2, 3] [999, 2, 3]

1. 얕은 복사(shallow copy)

1) 얕은 복사 - Slice 활용
  • Slice 연산자를 활용하여 같은 원소를 가진 리스트지만 연산된 결과를 복사함

  • 위의 할당과는 다르게, 각 변수는 다른 주소의 리스트를 참조함

  • 이 경우, 특정 리스트의 일부 값을 변경해도 나머지 리스트에 영향을 미치지 않음

  • 예시

    orgin_list = [1, 2, 3]
    copy_list = origin_list[:]
    copy_list[0] = 999
    print(origin_list, copy_list)
    
    => [1, 2, 3] [999, 2, 3]
2) 얕은 복사 - list() 활용
  • 얕은 복사 - list() 활용

    • list()를 활용하여 같은 원소를 가진 리스트지만 연산된 결과를 복사함
    • 마찬가지로 다른 주소를 참조하게 됨
  • 예시

    orgin_list = [1, 2, 3]
    copy_list = list(origin_list)
    copy_list[0] = 999
    print(origin_list, copy_list)
    
    => [1, 2, 3] [999, 2, 3]
  • 얕은복사 주의사항

    • 복사하는 리스트의 원소가 주소를 참조하는 경우
    • 리스트 내의 리스트는 여전히 같은 주소를 참조함
    • 예시
    # 얕은 복사 시,리 스트 내의 리스트 값을 변경하면?
    a = [1, 2, ['a', 'b']]
    b = a[:]
    b[2][0] = 0
    print(a, b)
    
    => [1, 2, [0, 'b']] [1, 2, [0, 'b']]
    
    # 얕은 복사를 했음에도, 리스트 안의 리스트 내 요소는 함께 변경됨을 알 수 있음

2. 깊은 복사(deep copy)

  • copy 모듈을 불러와서 실행

  • 예시

    import copy
    
    a = [1, 2, ['a', 'b']]
    b = copy.deepcopy(a)
    b[2][0] = 0
    print(a, b)
    
    => [1, 2, ['a', 'b']] [1, 2, [0, 'b']]
    

List Comprehension

  • 표현식과 제어문을 통해 특정한 값을 가진 리스트를 생성하는 법

  • 한 줄로 표현 가능함

  • 예시

    # 1 - 3의 세제곱 리스트 만들기
    # 일반적인 방법
    cubic_list = []
    for number in range(1, 4):
        cubic_list.append(number ** 3)
    print(cubic_list)
    
    => [1, 8, 27]
    
    # list comprehension을 활용해 한 줄로 만들어보기
    [number**3 for number in range(1, 4)]
    
    => [1, 8, 27]
    # 1 - 3 숫자 중 짝수만 담긴 리스트를 만들기
    # 일반적인 방법
    even_list = []
    for number in range(1, 4):
        if number % 2 == 0:
            even_list.append(number)
    print(even_list)
    
    => [2]
    
    # list comprehension을 활용해 한 줄로 만들어보기
    
    [x for x in range(1, 4) if x % 2 == 0]
    
    => [2]
    # 각 element를 짝지어 튜플 객체를 리스트에 담기
    girls = ['kim', 'lim']
    boys = ['lee', 'kwon']
    
    # 반복문 활용
    pair = []
    for boy in boys:
        for girl in girls:
            pair.append((boy, girl))
    
    => [('lee', 'kim'), ('lee', 'lim'), ('kwon', 'kim'), ('kwon', 'lim')]
    
    # list comprehension 이용
    [(boy, girl) for boy in boys for girl in girls]
    
    # 간략하긴 하나, 가독성이 좋진 않음
  • 위 예시처럼, 리스트를 한 줄로 만들 수 있다는 장점이 있으나 사용하는 것이 반드시 좋은 것은 아님

  • 가독성을 고려하면서 사용해야

    # map과 list comprehension의 유사성 
    
    # 변수 numbers 를 '123' 으로 만들어라
    numbers = [1, 2, 3]
    
    # list comprehension
    a = ''.join([str(num) for num in numbers])
    
    # map function
    b = ''.join(map(str, numbers))

Built-in Function - map()

  • 순회가능한 데이터 구조(iterable)의 모든 요소에 함수를 적용하고, 그 결과를 map object로 반환
  • 일반적으로 map object를 리스트로 형변환 하여 결과를 확인함
# 형식
map(function, iterable)

# 예시
numbers = [1, 2, 3]
result = map(str, numbers)
print(list(result))

=> ['1', '2', '3']
  • 알고리즘 문제 풀이 시 유용
# 정수 2개를 입력받을 때
n, m = map(int, input().split())

Built-in Function - filter()

  • 순회가능한 데이터 구조(iterable)의 모든 요소에 함수를 적용하고, 그 결과가 True인 것들을 filter object로 반환
  • map()은 함수 자체의 리턴값이 반환된다면, filter의 경우 함수의 리턴값이 True인 경우만 해당 값을 반환
  • 마찬가지로 리스트로 형변환하여 결과 확인
# 형식
filter(function, iterable)

# 예시
def odd(n):
    return n % 2

numbers = [1, 2, 3]
result = filter(odd, numbers)
print(list(result))

=> [1, 3]

Built-in Function - zip()

  • 복수의 iterable을 모아 튜플을 원소로 하는 zip object를 반환
  • 각 iterable의 원소의 개수가 맞지 않을 땐?
    • 동일한 갯수까지만 짝지어 반환되고, 나머지 원소는 무시됨
# 형식
zip(*iterable)

# 예시 - 각 리스트의 원소의 개수가 다를땐?
boys = ['lee', 'kwon', 'kang']
girls = ['kim', 'lim']
pair = zip(girls, boys)
print(list(pair))

=> [('kim', 'lee'), ('lim', 'kwon')]

세트

  • 특징

    • 변경 가능하고(mutable)
    • 순서가 없고(unordered)
    • 순회 가능함(iterable)

세트 관련 메서드

  • 값 추가/삭제

    • .add()

      • 세트에 값을 추가
      # 형식
      set.add(elem)
      
      # 예시
      fruits = ['사과', '바나나']
      fruits.add('딸기')
    • .update()

      • 여러 값을 추가
      # 형식
      set.update(*others)
      
      # 예시
      fruits = ['사과', '바나나']
      fruits.update(['딸기', '수박'])
    • .remove()

      • 세트에서 삭제하고, 없으면 KeyError
    • .discard()

      • 세트에서 삭제하고, 없어도 에러가 발생하지 않음
    • .pop()

      • 임의의 원소를 제거해 반환함 (set의 경우 unordered 이기 때문)
      • 세트가 비어있는 경우 keyError

딕셔너리

  • 특징
    • 변경 가능하고(mutable)
    • 순서가 없고(unordered)
    • 순회 가능함(iterable)

딕셔너리 관련 메서드

  • 조회

    • .get()

      • key에 대응하는 value 가져옴
      • key가 딕셔너리에 없어도 KeyError가 발생하지 않음
      • 인자로 넣어준 default를 돌려주며, 기본 값은 None
      # 형식
      .get(key[, default])
      
      # 예시
  • 추가 및 삭제

    • .pop()

      • key가 딕셔너리에 있으면 제거하고 해당 값을 반환
      • 그렇지 않으면 default를 반환
      • default 값이 없고 key가 딕셔너리에 없으면 keyError 발생
    • .update()

      • 값을 제공하는 key, value로 갱신 (기존 key는 덮어씀)
      fruits = {'apple': '사', 'banana': '바나나'}
      fruits.update(apple = '사과')
      print(fruits)
      
      => fruits = {'apple': '사과', 'banana': '바나나'}

딕셔너리 순회

  • 딕셔너리는 기본적으로 key를 순회하며, key를 통해 값을 활용
  • 추가 메서드를 활용하여 순회할 수 있음
    • keys() : Key로 구성된 결과
    • values() : Value로 구성된 결과
    • items() : (Key, Value)의 튜플로 구성된 결과

Dictionary Comprehension

  • 리스트만큼 자주 쓰진 않음

  • 가독성 의 문제

  • 예시

    # 다음의 딕셔너리에서 값이 70 이상으로 구성된 딕셔너리 만들라
    dusts = {'서울': 72, '대전': 82, '구미': 29, '광주': 45}
    
    result = {}
    for key, value in dusts.items():
        if value >= 70:
            result[key] = value
    print(result)
    
    # 위 과정을 Dictionary Comprehension 으로
    {key: value for key, value in dusts.items() if value > 70}

'Python' 카테고리의 다른 글

객체지향 프로그래밍  (0) 2021.08.30
객체  (0) 2021.08.30
제어문  (0) 2021.08.30
컨테이너  (0) 2021.08.30
2차원 리스트 생성  (0) 2021.08.01

댓글