ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Rust 강좌 7 - itertools
    Rust 2024. 10. 8. 22:16

    Rust 강좌 7 - itertools

    itertools 크레이트는 Haskell과 Python의 itertools에서 영감을 받은 여러 유틸리티 함수와 매크로를 포함하고 있는데요.

     

    이름에서 알 수 있듯이, 이는 반복(iteration)과 반복자(iterators)와 관련이 있습니다.

     

    itertools를 사용하려면, 다음과 같은 의존성 선언을 Cargo.toml에 추가하면 되는데요:

    [dependencies]
    itertools = "~0.0.4"

     

    우리는 도우미 함수부터 시작해서 나중에 매크로를 다룰 건데요.

     

    foreach

    이 함수와 몇몇 다른 함수는 Itertools 트레이트에 포함되어 있어서, 모듈에 use itertools::Itertools를 추가해 범위에 넣어야 하는데요.

     

    foreach()는 개념적으로 아주 간단한데요.

     

    (가변) 반복자를 소비하며, 각 요소에 대해 클로저를 호출합니다.

     

    반환 타입은 () (유닛)인데요, 이는 foreach()가 보통 호출 체인의 마지막에 있어야 한다는 뜻입니다.

     

    예를 들어:

    let mut words = "hello supercalifragilisticexpialidocious programmer".split(|c| c == ' ');
    words.foreach(|word| println!("{} is {} characters long", word, word.len()));

     

    보시다시피, foreach()는 표준 라이브러리의 map() 메서드와 유사한데요.

     

    하지만 map은 또 다른 반복자를 반환합니다.

     

    따라서 map은 게으르고(method chaining을 허용하는) foreach는 즉각적으로 실행되며 최종적으로 결과를 출력하게 됩니다.

     

    interleave와 intersperse

    interleave()zip()과 다소 유사한데요.

     

    하지만 zip이 두 개의 반복자로부터 튜플을 생성하는 반면, interleave는 두 반복자 간의 값을 번갈아 출력합니다.

    let even = (1..10).map(|x| x * 2);
    let odd = (1..5).map(|x| x * 2 + 1);
    println!("{:?}", even.interleave(odd).collect::<Vec<_>>());

     

    결과는 다음과 같은데요:

    $ cargo run
    [2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18]

     

    보시다시피, 반복자들이 반드시 동일한 수의 요소를 포함할 필요는 없는데요.

     

    이런 경우 interleave는 "더 짧은" 반복자가 소비된 이후에도 다른 반복자에서 값을 계속 출력합니다.

     

    Haskell의 대응 함수와 유사하게, intersperse는 단일 값과 반복자를 받아서 (암묵적으로 self 인자로) 감싸진 반복자의 각 요소 사이에 주어진 값을 출력하는데요.

     

    예를 들어:

    println!("{:?}", (1..10).intersperse(15).collect::<Vec<_>>());

     

    출력은 다음과 같아요:

    $ cargo run
    [1, 15, 2, 15, 3, 15, 4, 15, 5, 15, 6, 15, 7, 15, 8, 15, 9]

     

    iproduct!

     

    이제 itertools에서 제공하는 매크로로 시선을 돌려볼 건데요.

     

    때때로 리스트/배열/벡터의 데카르트 곱을 반복할 필요가 있는데요.

     

    보통은 두 개의 중첩 루프가 필요하지만, iproduct() 매크로를 사용하면 이를 단일 for 루프로 간소화할 수 있습니다.

    let numbers = 1..4;
    let chars = vec!['a', 'b', 'c'];
    for (i, c) in iproduct!(numbers, chars.iter()) {
        println!("{}: {}", i, c);
    }

     


     

Designed by Tistory.