Big Bro's Studying Archive

Python 기초 6 : for 반복문, map함수, 리스트 내포표현식을 이용한 리스트 연산 본문

Big Data展

Python 기초 6 : for 반복문, map함수, 리스트 내포표현식을 이용한 리스트 연산

빅브로오 2020. 4. 21. 14:58

"""
Created on Fri Apr 10 10:17:32 2020

@author: Yoon Baek
"""

로또 생성 프로그램 만들어보기

import random
lot = []
while len(lot) <= 7 :
    num = random.randrange(1,46)
    if num in lot :
        next
    else :
        lot.append(num)
    lot.sort(reverse = False)
print(lot)

random 모듈의 randrange 함수를 활용해
1번부터 45번까지의 숫자를 랜덤으로 출력하고 정렬하는 프로그램

리스트 내포 표현식

  • 리스트가 벡터연산이 안되는 점을 비교적 간단한 문법으로 가능하게 함
  • 리스트 내부에 반복문/조건문의 축약형 형태 전달 가능

1. 문법

[ 리턴값 for 반복변수 in 대상 ]                          # 반복만 가능
[ 리턴값 for 반복변수 in 대상 if 조건 ]                  # else 생략 가능
[ 참리턴값 if 조건 else 거짓리턴값 for 반복변수 in 대상 ] # else 선언

예제) 아래 리스트에 10% 인상된 값 리턴

L1 = [1,2,3,4,5]

1) for 문

L2 = []
for i in L1 :
    L2.append (i * 1.1)
L2

2) mapping

list(map(lambda x : x *1.1, L1))

3) list 내포 표현식

[i * 1.1 for i in L1]

예제2) 아래 리스트에서 3보다 작은 값만 출력

L1 = [1,2,3,4,5]

1) for문

L2 = []
for i in L1:
    if i < 3 :
        L2.append(i)
L2

2) map

list(map(lambda x : x if x < 3 else None, L1))

lambda에서 if를 쓸 때 else 생략이 안되고 간단한 if문만 가능하다.

3) list comprehension

[i for i in L1 if i < 3]             # 가능
[i for i in L1 if i < 3 else i * 2]  # 불가
[i  if i < 3 else i * 2 for i in L1] # 가능

예제3) L1 리스트에서 3보다 작으면 'a' 크거나 같으면 'b' 리턴

['a' for i in L1 if i < 3 else 'b'] # 불가
['a' if i < 3 else 'b' for i in L1] 

else값을 넣고 싶으면 if문을 통째로 앞으로 빼서 축약형으로 전달해야한다.

[ 연습 문제 ]

sal = ['9,900','25,000','13,000']
addr = ['a;b;c','aa;bb;cc','aaa;bbb;ccc']
comm = [1000,1600,2000]

위 리스트를 입력후 풀이해보자.

1) sal의 10% 인상값 출력

sol 1 : for 문

L2 = []

for i in sal:
    i = i.replace(',','')
    L2.append(round(int(i)*1.1))
L2

sol 2 : 매핑

f1 = lambda x : round(int(x.replace(',','')) * 1.1)
list(map(f1, sal))

sol 3 : 리스트 내포 표현식

[round(int(i.replace(',','')) * 1.1) for i in sal]

리스트 내포 표현식이 쿼리가 간단해서 애용하게 되는 듯 하다.
단 논리적 구조가 복잡할 때는 for문을 쓰게 되는 듯

2) addr에서 각 두번째 값(b,bb,bbb) 출력

sol 1 : for 반복문 이용

'b;b;b'.split(';')[1]
addr2 = []
for i in addr :
    addr2.append(i.split(';')[1])
addr2

sol 2 : 매핑함수 이용

f2 = lambda x : x.split(';')[1]
list(map(f2, addr))

[ 참고 - map에 인자 전달 방식 ]

fchamgo = lambda x, y : x.split(';')[y]
list(map(fchamgo,addr, 1))   # map에 스칼라 숫자 전달
list(map(fchamgo,addr, [1])) 

map은 서로 다른 리스트의 개수를 맞춰주는 기능이 없다.
따라서 아래와 같은 방식으로 사용자가 개수를 맞춰 전달해주어야 한다.

list(map(fchamgo,addr, [1,1,1]))

근데 언제까지 이런식으로 할 것인가?
pandas의 map 유사 기능이나 다른 적용함수는 가능한 것들이 있으므로 활용

sol 3 : 리스트 내포 표현식 활용

[ i.split(';')[1] for i in addr ]

3) comm이 1500보다 큰 경우 'A', 아니면 'B' 출력

sol 1

comm2 = []
for i in comm:
     if i > 1500 :
         comm2.append('A')
     else :
         comm2.append('B')
comm2

sol 2

f3 = lambda x : 'A' if x > 1500 else 'B'
list(map(f3, comm))

sol 3

['A' if i > 1500 else 'B' for i in comm]

sol 4 : np.where의 활용

np.where(np.array(comm) > 1500, 'A', 'B')  

numpy의 np.where 함수를 활용할 수 있다.
R의 ifelse함수와 똑같은 역할을 하는 함수.
다만 array에만 적용가능한 함수이므로
리스트인 경우 형을 array로 변환해주자.

deep copy

L1 = [1,2,3]
L2 = L1

L1 [0] = 10
L1
L2 

L2도 1번째 원소가 같이 변한 것을 확인
파이썬의 특징 : 메모리 공유

L2[2] = 9
L1          

L2를 바꿔도 L1이 변함

L1 = [1,2,3]
L1 = L3[:] 

메모리 분리 (완벽히 다른 개체)
백업을 원할 경우는 이렇게 해야.

[ 참고 : 객체의 메모리 주소 확인 ]

id(L1)      # 1287198669768
id(L2)      # 1287198669768 L1과 L2는 같음을 확인
id(L3)      # 1287198016136

[실습문제]

아래문제들은 난이도가 있음에 유의.
풀기 어렵더라도 집착하지 않아도 된다.

1. oracle translate와 같은 함수 생성

예시) f_translate('abcdea','abc','ABC') => 'ABCdeA'

def f_translate(word, target, change):
    if len(target) <= len(change):
        res = word
        for i in range(0,len(target)):
            for j in range(0,len(word)):
                if target[i] == word[j]:
                    res = res.replace(word[j],change[i])
                else :
                    pass
    elif len(change) != 0 :
        res = word
        for i in range(1, len(target)-len(change)+1):
            res = res.replace(target[-i],'')
        for i in range(0,len(change)):
            for j in range(0,len(res)):
                if target[i] == res[j]:
                    res = res.replace(res[j],change[i])
                else :
                    pass
    else :
        res = word
        for i in range(1, len(target)-len(change)+1):
            res = res.replace(target[-i],'')
    return(res)

f_translate('abcd  ea','a bc','ABC')

2. oracle instr과 같은 함수 생성(없으면 -1 생성)

예시) f_instr(data,pattern,start=0,n=1)
풀이 1

def f_instr(data, pattern, start = 0, n = 1):
    match = []
    for i in range(0, len(data)-len(pattern)+1):
        if data[i:i+len(pattern)] == pattern :
            match.append(i)
        else :
            next 
    if len(match) != 0:
        for j in range(0, len(match)):
            if match[j] < start :
                match.remove(j)
            else:
                next
        print(match[n - 1])
    else:
        print(-1)
match
    len(match)
'aaaaa'.find('a',3)
match[1]
f_instr('abcda','c', start = 1 ,n = 2)
match.remove(0)

풀이 2

def f_instr(data, pattern ,start, n):
    for i in range(0,n) :
        position = data.find(pattern, start)
        start = position + 1
    return position

f_instr('abcdae', 'a', 1, 2)

3. 1~100까지의 누적합 계산시 최초로 누적합이 1000을 넘는 숫자 출력

i = 0
vsum = 0
for i in range(1,101) :
    if vsum >= 1000 :
        break
    else :
        vsum += i
        i += 1
print ('%d에서 누적합이 1000을 넘습니다.' % i)

Comments