List comprehension

참고로 오늘 처음 들었음.

List comprehension-기본편

보통 파이썬에서 리스트는

a = list(range(9))
print(a)

이거 아니면

a = [0,1,2,3,4,5,6,7,8]

이걸로 만든다. 참고로 둘이 같은 리스트임. 근데 이걸 리스트 컴프리헨션으로 생성하면

a = list(i for i in range(9))
print(a)

이렇게 쓰거나

a = [i for i in range(100)]
print(a)

이렇게 대괄호 안에 때려박는다.

List comprehension에 반복문 넣기

참고로 내 신조가 ‘For문 가는데 While이 국룰’이었는데 얘는 예외다. While 넣어보려고 했는데 안됨… 아마 For문과 달리 while은 조건부 반복이라 그런 듯 하다.

a = list(2 ** i for i in range(9))
print(a)
[1, 2, 4, 8, 16, 32, 64, 128, 256]

별 거 없고 걍 이렇게 쓰면 된다.

a = list(i ** 2 for i in range(9))
print(a)
[0, 1, 4, 9, 16, 25, 36, 49, 64]

이건 자매품. (n의 2승)

List comprehension에 if문 넣기

def isprime(a):
    sqrt = int(a ** 0.5)
    if a == 1: 
        return False
    for i in range(2,sqrt+1):
        if a % i == 0:
            return False
    else: 
        return True

솔직히 홀짝은 너무 진부해서 이거 가져왔다. 어디서 많이 본 것 같다고? 이거 예전에 백준 소수파트 풀 때 개근했던 함수다.

a = [i for i in range(100) if isprime(i)]
print(a)
[0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

일단… 저 함수 자체를 좀 손봐야 하는 게, 백준 소수파트는 숫자가 작아봐야 1이다. 그래서 1보다 작은 수가 아니라 1일 때에 대한 처리를 한 거라 그 부분을 손봐야 한다.

def isprime(a):
    sqrt = int(a ** 0.5)
    if a <= 1: 
        return False
    for i in range(2,sqrt+1):
        if a % i == 0:
            return False
    else: 
        return True
# a == 1을 a <= 1로 바꿨다. 
a = [i for i in range(100) if isprime(i)]
print(a)
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

함수의 ==를 <=로 바꾸면 2부터 나오는 것을 볼 수 있다.

b = list(i for i in range(100) if i % 3 == 0)
print(b)
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99]

간단한 조건문은 이런 식. 근데 0은 왜 들어가있는겨… 애초에 저거 나눌수는 있는거냐

List comprehension에 여러개 넣기

a = [i * j for i in range(1,11) for j in range(1,5,2)]
print(a)
[1, 3, 2, 6, 3, 9, 4, 12, 5, 15, 6, 18, 7, 21, 8, 24, 9, 27, 10, 30]

반복문이 여러개 있을 때 처리는 뒤에놈부터다. 즉, 이 코드는 뒤에 있는 j(1,3)를 앞에 있는 i에 순차적으로 곱한 결과.

a = [i for i in range(1,101) if i % 2 == 0 and i % 4 == 2]
print(a)
[2, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62, 66, 70, 74, 78, 82, 86, 90, 94, 98]

조건문도 여러 개 넣을 수 있다. 위 코드는 2의 배수이면서 4의 배수가 아닌 수를 찾는 코드.

a = [i for i in range(1,101) if i % 2 == 0 if i % 3 == 0]
print(a)
[6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, 78, 84, 90, 96]

2와 3의 공배수, 즉 6의 배수를 찾는 코드. …근데 이게 이렇게 된다고? 저거 실화냐 


번외편: 뭐야 이게 왜 돼요?

a = ['{},{}'.format(i,j) for i in range(1,10) for j in range(1,10,2)]
print(a)
['1,1', '1,3', '1,5', '1,7', '1,9', '2,1', '2,3', '2,5', '2,7', '2,9', '3,1', '3,3', '3,5', '3,7', '3,9', '4,1', '4,3', '4,5', '4,7', '4,9', '5,1', '5,3', '5,5', '5,7', '5,9', '6,1', '6,3', '6,5', '6,7', '6,9', '7,1', '7,3', '7,5', '7,7', '7,9', '8,1', '8,3', '8,5', '8,7', '8,9', '9,1', '9,3', '9,5', '9,7', '9,9']

format 줘서 문자열로 리스트에 넣는 것도 된다. …쩌는데?

a = ['{},{}'.format(i,j) for i in range(1,10) for j in 'pikachu']
print(a)
['1,p', '1,i', '1,k', '1,a', '1,c', '1,h', '1,u', '2,p', '2,i', '2,k', '2,a', '2,c', '2,h', '2,u', '3,p', '3,i', '3,k', '3,a', '3,c', '3,h', '3,u', '4,p', '4,i', '4,k', '4,a', '4,c', '4,h', '4,u', '5,p', '5,i', '5,k', '5,a', '5,c', '5,h', '5,u', '6,p', '6,i', '6,k', '6,a', '6,c', '6,h', '6,u', '7,p', '7,i', '7,k', '7,a', '7,c', '7,h', '7,u', '8,p', '8,i', '8,k', '8,a', '8,c', '8,h', '8,u', '9,p', '9,i', '9,k', '9,a', '9,c', '9,h', '9,u']

문자열도 시퀀스 데이터라 for문 돌릴 수 있어서 저게 된다.

a = [ord(i) for i in 'ABCDEFG']
print(a)
a = [hex(ord(i)) for i in 'ABCDEFG']
print(a)

알파벳을 ASCII코드로 바꾸거나 그 아스키 번호 진수 바꾸는 것도 된다. 왜 되는거냐

번외편 2-튜플도 되나요?

a = (i for i in 'pikachu')
print(type(a))
<class 'generator'>

아뇨 안되는데요.

a = (i for i in range(1,10))
for i in a:
    print(i)

저렇게 만들어진 거 뽑으려면 for문 줘야 한다. Biopython 하면서 저런 비슷한 거 많이 봤음…

a = 'Eternatus'
b = tuple(ord(i) for i in a)
print(b)

튜플로 컴프리헨션 주고 싶으면 tuple()를 쓰자. 그건 왜 되는거냐

번외편 3-세트와 딕셔너리에도 되나요?

이쯤되면 문자열 빼고 어지간한 시퀀스 자료형은 다 해본 거 같은데… 아무튼 세트랑 딕셔너리도 생각난 김에 해봤음.

a = {i for i in range(10)}
print(a)
a = set(i for i in 'apple')
print(a)

둘 다 먹힌다. …왜?

a = {i:j for i in range(9) for j in range(9) if i % 2 == 0)
print(a)

딕셔너리는 먹히긴 먹히는데 키값이 같으면 죄다 버리기때문에 최종 출력이 리스트보다 짧다. (각 키별로 밸류에 8이 들어감)