ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [BOJ#1316] sorted(s,key=s.find), generator, iterable, iterator 개념
    Programming 기초/Coding Test 2023. 7. 19. 02:45

    * 그룹 단어 체커(1316번)

    더보기

    <문제>

    그룹 단어란 단어에 존재하는 모든 문자에 대해서, 각 문자가 연속해서 나타나는 경우만을 말한다. 예를 들면, ccazzzzbb는 c, a, z, b가 모두 연속해서 나타나고, kin도 k, i, n이 연속해서 나타나기 때문에 그룹 단어이지만, aabbbccb는 b가 떨어져서 나타나기 때문에 그룹 단어가 아니다.

    단어 N개를 입력으로 받아 그룹 단어의 개수를 출력하는 프로그램을 작성하시오.

     

    <입력>

    첫째 줄에 단어의 개수 N이 들어온다. N은 100보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에 단어가 들어온다. 단어는 알파벳 소문자로만 되어있고 중복되지 않으며, 길이는 최대 100이다.

    <출력>

    첫째 줄에 그룹 단어의 개수를 출력한다.

    # 내 답변
    # 연속해서 중복되는 글자들을 지운 새로운 리스트(ss)를 만들고
    # len(ss)==len(set(ss))를 비교한다.
    
    import sys
    input=sys.stdin.readline
    n=int(input())
    cnt=0
    for _ in range(n):
        s=list(input())
        if len(s)==len(set(s)): cnt+=1
        else:
            back=" "
            ss=[]
            for w in s:
                if w==back and w in ss:
                    back=w
                    continue
                else : 
                    ss.append(w)
                    back=w
            if len(ss)==len(set(ss)):
                cnt+=1
    print(cnt)

     

    # 고수의 짧은 답변
    print(sum([*x]==sorted(x,key=x.find)for x in open(0))-1)

    위 코드의 sum()함수 안에 들어있는 객체의 타입은 'generator'이다. list, tuple, set, dictionary와 같이 이전에 배운 iterable 객체(순회가능한 객체)들과 비슷하면서 다르다. sum은 iterable 객체를 인자로 받아서 요소들의 합산을 구한다.

    generator 설명↓

    더보기

    Iterable

    __iter__라는 메소드를 구현한 객체를 iterable 객체라고 한다. 반복 가능한 객체.

    여기서 반복은 한 번에 하나의 요소를 가져오는 것을 말한다.

     

    Iterator

    iterable 객체에 iter()함수를 호출하면 iterator가 된다. iterator는 next() 또는 __next__ 메소드를 사용할 수 있고, 다음 요소에 접근할 수 있다.

    iterator는 모든 동작을 완료한 후 결과를 한꺼번에 메모리에 적재시킨다. for 문을 사용할 때는 iterable 객체를 그대로 사용하는데, 그 이유는 for 문의 내부에서 자체적으로 iterable 객체를 iterator로 만들어주기 때문이다.

    < for 문의 내부 코드 >
    # create an iterator object from that iterable
    iter_obj = iter(iterable)
    
    # infinite loop
    while True:
        try:
            # get the next item
            element = next(iter_obj)
            # do something with element
        except StopIteration:
            # if StopIteration is raised, break from loop
            break

    # dir()를 사용하면 객체 내부에 어떤 메서드가 존재하는지 확인할 수 있다.

     

    generator를 사용하는 이유

    1. generator는 특별한 iterator이다. 모든 generator는 iterator이다.

    2. iterator의 특징인  __next__와 __iter__ 메서드 사용을 피하고 yield를 사용하는 우아하고 간결한 파이썬스러운 방식이다.

    3. 필요하면 그때 그때 값을 생성하기 때문에 메모리 공간 절약에 도움이 된다.

     

    generator에서 yield.(출처 : chatGPT)

    제너레이터는 함수와 유사한 문법으로 정의되며, 값을 생성하는 yield 키워드를 사용합니다. yield 키워드는 값을 반환하고 제너레이터의 상태를 일시적으로 정지시키는 역할을 합니다. 이후에 제너레이터가 다시 호출되면, yield 문 이후의 코드 실행부터 다음 yield 문을 만날 때까지 실행됩니다.

    제너레이터는 함수의 실행 흐름을 제어할 수 있는 장점이 있습니다. 함수 호출이 발생할 때마다 값을 계산하고 필요한 만큼만 반환하여 처리할 수 있습니다. 이로 인해 반복 작업에 유용하며, 데이터 스트림 처리, 대규모 데이터셋의 처리, 무한 수열 생성 등에 활용될 수 있습니다.

     

    yield의 주요 목적은 다음과 같습니다:

    1. 값의 생성: yield 문은 제너레이터에서 값을 반환하는 역할을 합니다. 제너레이터 함수의 실행이 yield에 도달하면, 해당 값을 반환하고 실행을 일시 중단합니다. 제너레이터는 다음 호출 시 yield 문 이후부터 실행을 재개하며, 다음 값을 생성할 수 있습니다.
    2. 일시적인 정지와 상태 유지: yield 문을 만나면 제너레이터의 상태가 일시적으로 정지됩니다. 제너레이터 함수의 로컬 변수와 실행 상태는 yield 문 이후로 유지되며, 다음 호출 시에는 이전 상태에서 실행을 재개할 수 있습니다. 이는 제너레이터가 값을 생성하면서도 실행 컨텍스트를 유지하고, 상태를 유연하게 관리할 수 있게 해줍니다.
    3. 지연 평가: 제너레이터는 필요에 따라 값을 계산하고 반환하기 때문에, 지연 평가(lazy evaluation)의 개념을 구현할 수 있습니다. 제너레이터는 호출자가 값을 요청할 때까지 연산을 수행하지 않으며, 필요한 값만 계산하여 반환합니다. 이는 대규모 데이터셋이나 무한 수열과 같이 계산 비용이 큰 작업에서 효율적인 처리를 가능하게 합니다.

    yield 키워드를 사용하여 값을 생성하고 제어의 흐름을 잠시 정지시키는 것으로, 제너레이터는 반복 작업, 데이터 스트림 처리, 상태 유지 등 다양한 상황에서 유용하게 활용됩니다. yield를 통해 제너레이터는 값을 필요에 따라 생성하고 유지하며, 호출자에게 필요한 값을 제공하는 강력한 도구로 사용됩니다.

    def countdown(n):
        while n > 0:
            yield n
            n -= 1
    
    
    # 제너레이터 호출 및 값 사용
    generator = countdown(5)
    print(next(generator))  # 5
    print(next(generator))  # 4
    print(next(generator))  # 3

    * sorted(s,key=s.find)

    s는 문자열을 담고 있는 변수라고 할 때,

    key=s.find의 의미는 "문자열의 각 요소에 대한 인덱스를 기준으로 정렬을 하라."이다.

     

    sorted의 key에 대한 포스팅참고

    정렬은 안정적임이 보장된다.(추가 설명보기↓)

    더보기

    정렬은 안정적임이 보장됩니다. 즉, 여러 레코드가 같은 키를 가질 때, 원래의 순서가 유지됩니다.

    >>>data = [('red', 1), ('blue', 1), ('red', 2), ('blue', 2)]
    >>>sorted(data, key=itemgetter(0))
    [('blue', 1), ('blue', 2), ('red', 1), ('red', 2)]

     

    blue에 대한 두 레코드가 원래 순서를 유지해서 ('blue', 1)이 ('blue', 2)보다 앞에 나옴이 보장됨에 유의하십시오.

    from operator import itemgetter
    data = [('red', 1), ('blue', 3), ('red', 2), ('blue', 2)]
    print(sorted(data, key=itemgetter(0)))      # 여기서 "itemgetter(0)"는  "lambda x : x[0]" 와 같다.
    print(sorted(data))
    ----------------------------------------------
    [('blue', 3), ('blue', 2), ('red', 1), ('red', 2)]
    [('blue', 2), ('blue', 3), ('red', 1), ('red', 2)]

     

    * 참고

    https://docs.python.org/ko/3/howto/sorting.html

     

    iterable, iterator, generator에 대해 잘 정리한 글.

    https://velog.io/@sawol/Iterable-Iterator-%EA%B7%B8%EB%A6%AC%EA%B3%A0-generator

     

    Iterable, Iterator 그리고 generator

    파이썬을 조금만 공부하다보면 마주치는 iterable과 iterator를 제대로 정리해보려고 한다. 분명 이전에도 이터레이블과 이터레이터에 대해 공부를 했는데 제대로 이해가 된 것이 아닌지, 볼 때마다

    velog.io

    https://velog.io/@sawol/Python#%EC%A0%9C%EB%84%88%EB%A0%88%EC%9D%B4%ED%84%B0

     

    꼭 필요한 파이썬 기초지식

    Life is too short, You need python.

    velog.io

     

    댓글

Designed by Tistory.