파이썬을 파이썬답게(Programmers)

jaehyukchoi·2021년 2월 11일
1

파이썬을 파이썬답게

  • map 의 활용

    • 2차원 리스트의 각각의 길이를 구하려고 할 때,

    • answer = []
      for i in mylist:
          answer.append(len(i))
    • 이렇게 하게 된다. 이건 파이썬다운 코드가 아님.

    • map을 활용해

    • list(map(len, mylist))
      # list(map(int, input().split())) 하는 것처럼
      # map아~ int형으로 바꿔줘~
    • 이런 식으로 map아 len처리해줘 mylist를. 그리고 그걸 list에 담으면 더욱 파이썬다운 코드가 된다

  • divmod

    • 몫과 나머지를 구할 때

    • a = 7
      b = 5
      print(*divmod(a, b))
    • 이렇게 divmod를 활용해 몫과 나머지를 한번에 구할 수 있고 unpacking을 활용해 tuple에 담긴 몫, 나머지 각각을 꺼내어 출력할 수 있다.

  • enumerate

    • 반복문을 돌릴 때 몇 번째 반목문인지 확인하기 위해 len을 range에 넣어서 하는 경우가 많았는데

    • lst = [4,1,5,8,2,9]
      for i in enumerate(lst):
          print(i)
      '''
      (0, 4)
      (1, 1)
      (2, 5)
      (3, 8)
      (4, 2)
      (5, 9)
      '''
    • 이런 식으로 enumerate를 활용하면 idx번호와 원소를 tuple형태로 반환해준다.

    • lst = [4,1,5,8,2,9]
      for idx, i in enumerate(lst):
          print(idx, i)
      '''
      0 4
      1 1
      2 5
      3 8
      4 2
      5 9
      '''
    • tuple형태 반환을 이용해서 이렇게 쓸 수도 있다.

  • 진법 변환

    • num = '3212'
      base = 5
      
      answer = 0
      for idx, i in enumerate(num[::-1]):
          answer += int(i) * ( base ** idx )
    • 이렇게 enumerate를 활용해 answer에 각각을 더해줄 수도 있지만

    • num = '3212'
      base = 5
      answer = int(num, base)
    • 기본적인 함수를 잘 써서 간단하게 쓸 수 있다

    • str형태의 숫자를 int형으로 바꾸면서 진법을 설정할 수 있는 것 같다.+

    • (추가) int함수는 '3212'라는 5진법의 수를 => 10진수로 바꿔줘. 라는 뜻이네

    • 10진수를 n진수로 바꾸고 싶다면

    • import string
      tmp = string.digits + string.ascii_lowercase
      def convert(num, base):
          q, r = divmod(num, base)
          if q == 0:
              return tmp[r]
          else:
              return convert(q, base) + tmp[r]
  • 문자열 정렬하기 -ljust, center, rjust

    • abc      
         abc   
            abc
    • 이렇게 공백을 넣어서 출력하고 싶을 때

    • s = 'abc'
      n = 7
      print(s.ljust(n))
      print(s.center(n))
      print(s.rjust(n))
  • 알파벳 출력하기 - string 모듈

    • import string 
      
      string.ascii_lowercase # 소문자 abcdefghijklmnopqrstuvwxyz
      string.ascii_uppercase # 대문자 ABCDEFGHIJKLMNOPQRSTUVWXYZ
      string.ascii_letters #대소문자 모두 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
      string.digits # 숫자 0123456789
  • sort와 sorted

    • sort는 원본 자체를 바꿔 버린다
    • sorted는 원본을 바꾸지 않고 sorted된 리스트를 새로 만들 수 있다.
  • 2차원 리스트 뒤집기 (★zip★)

    • zip은 동일한 개수로 이루어진 자료형을 묶어 주는 역할을 하는 함수

    • >>> list(zip([1, 2, 3], [4, 5, 6]))
      [(1, 4), (2, 5), (3, 6)]
      >>> list(zip([1, 2, 3], [4, 5, 6], [7, 8, 9]))
      [(1, 4, 7), (2, 5, 8), (3, 6, 9)]
      >>> list(zip("abc", "def"))
      [('a', 'd'), ('b', 'e'), ('c', 'f')]
    • # 내 풀이
      def solution(mylist):
          answer = []
          for i in range(len(mylist)):
              temp = []
              for j in range(len(mylist)):
                  temp.append(mylist[j][i])
              answer.append(temp)
              
          return answer
    • 또는

    • new_list = [[], [], []]
      
      for i in range(3):
          for j in range(3):
              new_list[i].append(mylist[j][i])
    • 보통은 이렇게 2중 for문으로 2차원 리스트를 뒤집는다

    • python에서는 zip과 unpacking을 활용해 코드 한 줄로 리스트를 뒤집을 수 있다

    • mylist = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
      new_list = list(map(list, zip(*mylist)))
      1. unpacking 하면 [1,2,3][4,5,6] [7,8,9] 가 되고
      2. 다음 zip을 하고 list화 하면 [(1,4,7), (2,5,8), (3,6,9)]
      3. 각각을 다 list화 해주어야 하니깐 map을 이용해서 map아 각각 다 list해줘~
      4. 그러면 map object가 만들어지고 이걸 다시 list화 해서 출력
    • zip 사용 예시

    • mylist = [1, 2, 3]
      new_list = [40, 50, 60]
      for i in zip(mylist, new_list):
          print (i)
      
      (1, 40)
      (2, 50)
      (3, 60)
    • 이렇게 하면 zip으로 묶은 tuple 각각이 i에 담기나 보다

    • list1 = [1, 2, 3, 4]
      list2 = [100, 120, 30, 300]
      list3 = [392, 2, 33, 1]
      answer = []
      for i, j, k in zip(list1, list2, list3):
         print(i + j + k)
    • 이건 zip으로 묶은 게 다시 i, j, k로 나눠서 각각 대입되고

    • animals = ['cat', 'dog', 'lion']
      sounds = ['meow', 'woof', 'roar']
      answer = dict(zip(animals, sounds)) # {'cat': 'meow', 'dog': 'woof', 'lion': 'roar'}
    • zip으로 묶은 tuple을 dict생성자를 활용해서 딕셔너리로 만들 수도 있다.

  • i번째 원소와 i+1번째 원소 - zip

    • # 내 풀이
      def solution(mylist):
          answer = []
          for i in range(len(mylist)-1): # 0 1 2 3 4 5
              cha = mylist[i]-mylist[i+1]
              answer.append(abs(cha))
          return answer
    • # zip 활용
      def solution(mylist):
          answer = []
          for number1, number2 in zip(mylist, mylist[1:]):
              answer.append(abs(number1 - number2))
          return answer
      '''
      mylist: [83, 48, 13, 4, 71, 11]
      mylist[1:]: [48, 13, 4, 71, 11]
      이렇게 두 개의 iterable한 객체의 길이가 다를 때
      zip을 활용해 합치면 짧은 쪽 길이에 맞춰진다.
      '''
  • 모든 멤버의 type 변환하기 -map

    • def solution(mylist):
          return list(map(int, mylist))
    • BOJ, SWEA 문제 풀 때 map을 이용해서 각각을 int 형으로 바꾸는 건 자주 쓰고 있었음. 저 int 자리에 다른 함수를 넣어서 다양하게 사용할 수 있다.

  • sequence 멤버를 하나로 붙이기 - join

    • 문자열 배열 ['1', '100', '33']을 이어 붙여 문자열 '110033' 만들기

    • 정수형 튜플 (3, 22, 91)을 이어붙여 문자열 '32291' 만들기

    • my_list = ['1', '100', '33']
      answer = ''.join(my_list)
    • 공백으로 붙여라. join을 이용해서. mylist를.

    • answer = ';'.join(my_list)
      # 1;100;33"
    • 이렇게 하면 세미콜론이 사이에 들어감

  • sequence type의 * 연산

    • 'abc', 'abcabc', 'abcabcabc', 'abcabcabcabc ...' 과 같이 'abc'가 n번 반복되는 문자열 만들기

    • [123, 456, 123, 456, 123 ...] 과같이 123, 456이 n번 반복되는 리스트 만들기

    • n = 어쩌고
      answer = 'abc'*n
    • n = 어쩌고
      answer= [123, 456]*n
  • 곱집합 구하기 - product

    • 예시) 두 스트링 'ABCD', 'xy' 의 곱집합은 Ax Ay Bx By Cx Cy Dx Dy 입니다.

    • import itertools
      
      iterable1 = 'ABCD'
      iterable2 = 'xy'
      iterable3 = '1234'
      itertools.product(iterable1, iterable2, iterable3)
      print(list(itertools.product(iterable1, iterable2, iterable3)))
      # [('A', 'x', '1'), ('A', 'x', '2'), ('A', 'x', '3'), ('A', 'x', '4'), ('A', 'y', '1'), ...
  • 2차원 리스트를 1차원 리스트로 만들기

    • [['A', 'B'], ['X', 'Y'], ['1']] => ['A', 'B', 'X' ,'Y', '1']

    • # 내 풀이
      def solution(mylist):
          ans = []
          for li in range(len(mylist)):
              for i in mylist[li]:
                  ans.append(i)
          return ans
    • # 보통 사람들
      my_list = [[1, 2], [3, 4], [5, 6]]
      answer = []
      for i in my_list:
          answer += i
      '''
      i에 [1,2] [3,4] [5,6]이 각각 들어올텐데
      이걸 append안하고 그냥 +로 붙여주면
      1차원으로 만들어지겠구나
      '''
    • my_list = [[1, 2], [3, 4], [5, 6]]
      
      # 방법 1 - sum 함수
      answer = sum(my_list, [])
      
      # 방법 2 - itertools.chain
      import itertools
      list(itertools.chain.from_iterable(my_list))
      
      # 방법 3 - itertools와 unpacking
      import itertools
      list(itertools.chain(*my_list))
      
      # 방법 4 - list comprehension 이용
      [element for array in my_list for element in array]
      
      # 방법 5 - reduce 함수 이용 1
      from functools import reduce
      list(reduce(lambda x, y: x+y, my_list))
      
      # 방법 6 - reduce 함수 이용 2
      from functools import reduce
      import operator
      list(reduce(operator.add, my_list))
  • 순열과 조합

    • 숫자를 담은 일차원 리스트, mylist에 대해 mylist의 원소로 이루어진 모든 순열을 사전순으로 리턴하는 함수 solution을 완성해주세요.

    • # 내 코드
      # input: [1, 2, 3]
      # output: [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
      from itertools import permutations
      def solution(mylist):
          mylist.sort()
          perms = list(map(list, permutations(mylist)))
          return perms
    • 'A', 'B', 'C'로 만들 수 있는 경우의 수 -> 'ABC', 'ACB', 'BAC', 'BCA', 'CAB', 'CBA'

    • import itertools
      
      pool = ['A', 'B', 'C']
      print(list(map(''.join, itertools.permutations(pool)))) # 3개의 원소로 수열 만들기
      print(list(map(''.join, itertools.permutations(pool, 2)))) # 2개의 원소로 수열 만들기
      1. 처음 permutations를 구하면 하나의 object가 나오고
      2. 단순히 list화 시키면 [('A', 'B', 'C'), ('A', 'C', 'B'), ('B', 'A', 'C'), ('B', 'C', 'A'), ('C', 'A', 'B'), ('C', 'B', 'A')] 이렇게 나온다
      3. 이걸 붙이고 싶으면 map과 join을 이용해서 map object를 만들고
      4. 이후 list화 시켜서 출력하면 된다.
  • 가장 많이 등장하는 알파벳 찾기 - Counter

    • # 내 코드
      # input: 'dfdefdgf'
      # output: 'df'
      my_str = input().strip()
      dic = {}
      for i in my_str: # a a b
          if i not in dic:
              dic[i] = 1
          else:
              dic[i] += 1
      max_val = max(dic.values())
      ans = ''
      for key, val in dic.items():
          if val == max_val:
              ans += key
              
      lst = sorted(list(ans))
      print(''.join(lst))
    • collections.Counter를 이용해서 리스트 원소 각각을 key로 하고 원소 갯수를 value로 하는 dict를 만들 수 있다. 인자로는 str과 list형태 모두 가능.

    • import collections
      my_str = input().strip()
      dic = collections.Counter(my_str)
      max_val = max(dic.values())
      ans = ''
      for key, val in dic.items():
          if val == max_val:
              ans += key
      lst = sorted(list(ans))
      print(''.join(lst))
      # my_list = [1, 2, 3, 4, 5, 6, 7, 8, 7, 9, 1, 2, 3, 3, 5, 2, 6, 8, 9, 0, 1, 1, 4, 7, 0]
      # my_str = 'dfdefdgf'
      # 두 경우 모두 Counter 이용해 dict로 만들 수 있음.
  • for문과 if문을 한번에

    • 정수를 담은 리스트 mylist를 입력받아, 이 리스트의 원소 중 짝수인 값만을 제곱해 담은 새 리스트를 리턴하는 solution함수를 완성해주세요예를 들어, [3, 2, 6, 7]이 주어진 경우

      • 3은 홀수이므로 무시합니다.
      • 2는 짝수이므로 제곱합니다.
      • 6은 짝수이므로 제곱합니다.
      • 7은 홀수이므로 무시합니다.

      따라서 2의 제곱과 6의 제곱을 담은 리스트인 [4, 36]을 리턴해야합니다.

    • # 내 코드
      # 파이써닉한 코드
      def solution(mylist):
          answer = [i**2 for i in mylist if i % 2==0]
          return answer
  • flag OR for-else

    • 본 문제에서는 자연수 5개가 주어집니다.

      1. 숫자를 차례로 곱해 나온 수가 제곱수가 되면 found를 출력하고
      2. 모든 수를 곱해도 제곱수가 나오지 않았다면 not found를 출력하는 코드를 작성해주세요
    • # 내 코드
      import math
      temp = 1
      for i in range(5):
          n = int(input())
          temp *= n
          if math.sqrt(temp) % 1 == 0:
              print('found')
              break
      else:
          print('not found')
    • # 보통 flag를 이용해서 푼다
      import math
      numbers = [int(input()) for _ in range(5)]
      multiplied = 1
      flag = True
      for number in numbers:
          multiplied *= number
          if math.sqrt(multiplied) == int(math.sqrt(multiplied)):
              flag = False
              print('found')
              break
      
      if flag:
          print('not found')
    • # 제시 방법
      import math
      numbers = [int(input()) for _ in range(5)]
      multiplied = 1
      for number in numbers:
          multiplied *= number
          if math.sqrt(multiplied) == int(math.sqrt(multiplied)):
              print('found')
              break
      else:
          print('not found')
    • for else 문은 보통 break랑 같이 사용하는 것 같은데, for문을 도는 동안에 원하는 어떤 일이 일어나면 그것을 출력하든지 return하든지 하고 break를 이용해 빠져나온다. for문을 다 돌았는데도 원하는 일이 일어나지 않으면 else문으로 가서 어떤 일을 하게 된다.

    • 나는 for문을 돌면서 input값을 차례로 받아왔는데 제시 방법에서는 input을 한 번에 받아 리스트에 넣었다

    • 제곱수인지 확인할 때 나는 math.sqrt를 이용해 루트를 씌운 값이 1로 나누어 떨어지면 제곱수라고 판단했고, 제시 방법에서는 루트를 씌운 값과 루트를 씌운 값의 정수형이 같은지 확인해 제곱수라고 판단했다

      • 10의 경우 루트를 씌우면 약 3.16 이 나오고 int형으로 바꿔주면 3이 나온다. 두 개가 다른 값이므로 제곱수 아님
      • 9의 경우 루트를 씌우면 3. int형으로 바꿔줘도 3. 같은 값이므로 제곱수 맞음.
  • 두 변수의 값 바꾸기 - swap

    • a = 3
      b = 'abc'
      
      a, b = b, a 
      # 보통 temp를 이용해서 하지만 이렇게 간단하게 바꿔치기할 수 있음.
  • 이진 탐색하기 - binary search

    • 이진 탐색: 이진 검색 알고리즘(binary search algorithm)은 오름차순으로 정렬된 리스트에서 특정한 값의 위치를 찾는 알고리즘이다. 처음 중간의 값을 임의의 값으로 선택하여, 그 값과 찾고자 하는 값의 크고 작음을 비교하는 방식을 채택하고 있다. 처음 선택한 중앙값이 만약 찾는 값보다 크면 그 값은 새로운 최댓값이 되며, 작으면 그 값은 새로운 최솟값이 된다. 검색 원리상 정렬된 리스트에만 사용할 수 있다는 단점이 있지만, 검색이 반복될 때마다 목표값을 찾을 확률은 두 배가 되므로 속도가 빠르다는 장점이 있다.

    • import bisect
      mylist = [1, 2, 3, 7, 9, 11, 33]
      print(bisect.bisect(mylist, 3))
    • 직접 구현할 필요 없이 bisect.bisect를 사용해 간단하게 가능.

    • bisect_left, bisect_right도 나중에 알아보기

  • 클래스 인스턴스 출력하기 - class의 자동 string casting

    • 인스턴스 출력 형식을 지정하는 방법!

    • 보통 클래스 바깥에 출력 함수를 만들거나, print문에서 format을 지정

    • # 보통 사람들
      class Coord(object):
          def __init__ (self, x, y):
              self.x, self.y = x, y
      
      point = Coord(1, 2)
      print( '({}, {})'.format(point.x, point.y) ) 
      
      # 또는
      def print_coord(coord):
          print( '({}, {})'.format(coord.x, coord.y) )
      print_coord(point)
    • # 제시 방법
      class Coord(object):
          def __init__ (self, x, y):
              self.x, self.y = x, y
          def __str__ (self):
              return '({}, {})'.format(self.x, self.y)
      
      point = Coord(1, 2)
    • 파이썬에서는 __str__ 메소드를 사용해 class 내부에서 출력 format을 지정할 수 있다.

    • 클래스에 대한 강의도 나중에 더 알아보기

  • 가장 큰 수, inf

    • 알고리즘 문제 풀 때 Max = -1, Min = 99999999 이런 식으로 임의의 수를 저장해서 사용했음
    • float('inf') 는 어떤 숫자와 비교해도 무조건 크다고 판정됨.

[출처] Programmers

profile
웹, AI 개발 공부.

1개의 댓글

comment-user-thumbnail
2021년 2월 21일

화이팅

답글 달기