paint-brush
SeqGen: 시퀀스 생성을 위해 만든 라이브러리by@crazyrat
530
530

SeqGen: 시퀀스 생성을 위해 만든 라이브러리

crazyrat7m2023/12/15
Read on Terminal Reader

시퀀스(비공식적으로 말하면)는 각 요소의 생성이 이전 요소를 기반으로 하는 요소 집합(주로 숫자)입니다. 가장 기본적인 예는 첫 번째 요소가 0이고 다음 요소가 이전 요소에 1을 더한 양의 정수의 간단한 선형 시퀀스이므로 첫 번째 요소에 1을 더하여 두 번째 요소를 얻을 수 있고 세 번째 요소를 얻을 수 있습니다. 두 번째 요소에 1을 추가하는 식으로 요소를 추가합니다. 선형 시퀀스는 다음과 같습니다: {0, 1, 2, 3, …, n}.
featured image - SeqGen: 시퀀스 생성을 위해 만든 라이브러리
crazyrat HackerNoon profile picture

소개:

시퀀스를 생성할 수 있는 라이브러리를 인터넷에서 검색하면 거의 찾을 수 없습니다. 하지만 시퀀스는 이산수학과 컴퓨터 과학의 핵심 개념입니다.


이 짧은 기사에서는 SeqGen 이라는 시퀀스 생성을 위해 제가 작성한 라이브러리를 살펴보겠습니다.

시퀀스란 무엇입니까?

시퀀스(비공식적으로 말하면)는 각 요소의 생성이 이전 요소를 기반으로 하는 요소 집합(주로 숫자)입니다.


가장 기본적인 예는 첫 번째 요소가 0이고 다음 요소가 이전 요소에 1을 더한 양의 정수의 간단한 선형 시퀀스이므로 첫 번째 요소에 1을 더하여 두 번째 요소를 얻을 수 있고 세 번째 요소를 얻을 수 있습니다. 두 번째 요소에 1을 추가하는 방식으로 요소를 구성합니다. 선형 시퀀스는 다음과 같습니다: {0, 1, 2, 3, …, n} .


더 복잡한 예는 처음 두 요소가 0과 1이고 다음 요소가 이전 두 요소의 합인 피보나치 수열일 수 있습니다. 피보나치 수열은 다음과 같습니다: {0, 1, 1, 2, 3, 5, 8, 13, 21, …, n}


위에서 시퀀스는 두 가지 속성으로 정의되어 있음을 알 수 있습니다.

  • 초기 요소
  • 다음 요소를 생성하는 함수

라이브러리 사용:

2.0_ 종속성:

SeqGen 라이브러리는 Rust 프로그래밍 언어로 작성되었습니다. 후속 조치를 취하려면 Rust가 설치되어 있어야 합니다.

2.1_ 프로젝트 생성:

SeqGen 라이브러리를 사용하기 위해 새 프로젝트를 만들어 보겠습니다. 화물로 그렇게 할 수 있습니다:

 $ cargo new --bin sequence && cd sequence


이제 프로젝트에 종속성으로 라이브러리를 추가해 보겠습니다.

 $ cargo add seqgen


이제 라이브러리를 사용할 준비가 되었습니다.

시퀀스 생성:

SeqGen에서 시퀀스 생성 프로세스는 시퀀스란 무엇입니까 섹션에서 결론을 내린 시퀀스의 두 가지 속성에 직접 매핑됩니다. 초기 요소와 다음 요소를 생성하는 함수(SeqGen에서는 전환 함수라고 함)를 정의해야 합니다.


선형 시퀀스를 만들어 보겠습니다.

 use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new() .initial_elements(vec![0]) .transition_function(|alive_elements, current_element_index| { alive_elements.last_element().unwrap() + 1 }); }


Sequence 유형은 시퀀스를 나타내는 구조체입니다. 이 유형에 대해 연관된 함수 new() 호출하면 정의되지 않은 새 인스턴스를 얻습니다. 정의되지 않은 이 인스턴스에서는 메서드를 호출하여 정의할 수 있습니다.


첫 번째 메소드는 요소의 벡터를 인수로 받아들이고 이를 인스턴스의 초기 요소로 설정하는 initial_elements() 입니다.


두 번째 메소드는 현재 사용 가능한 요소에서 다음 요소로의 전환을 나타내는 클로저를 인수로 사용하는 transition_function() 입니다.


이 클로저는 두 개의 인수에 액세스할 수 있습니다. 첫 번째는 현재 사용 가능한 요소를 나타내는 alive_elements 이고, 두 번째는 생성 중인 현재 요소의 인덱스인 current_element_index ( usize 유형)입니다. 전환 기능에 대한 설명은 아래 표를 참조하세요.


현재 세대 요소

살아있는_요소

현재_요소_색인

1

[0]

1

2

[0, 1]

2

3

[0, 1, 2]

3

n

[0, 1, 2, 3, …, n]

n


alive_elementsSequencePart 유형입니다. 이 기사의 뒷부분에서 SequencePart 유형을 살펴보겠습니다.


요소의 인덱스는 선형 시퀀스의 값이기도 하므로 위의 예를 다음과 같이 단순화할 수 있습니다.

 use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new().transition_function(|_, i| i); }


여기서는 초기 요소를 정의할 필요가 없으며 라이브 요소에 액세스할 필요도 없습니다. 우리는 인덱스(이 경우 이름은 i )만 필요하고 간단히 반환합니다.


같은 방식으로 피보나치 수열을 정의할 수 있습니다.

 use seqgen::prelude::*; fn main() { let fib_seq = Sequence::new() .initial_elements(vec![0, 1_u128]) .transition_function(|alive_elements, i| { let x = alive_elements.nth_element(i - 1).unwrap(); let y = alive_elements.nth_element(i - 2).unwrap(); x + y }); }

피보나치 수열은 기하급수적으로 증가하므로 이 정의로 187개 이상의 요소를 생성하면 u128 오버플로됩니다. 더 나은 정의는 u128 대신 big int를 사용하는 것입니다.

시퀀스 사용 :

시퀀스를 정의한 후에는 해당 요소에 액세스할 수 있습니다.

 use seqgen::prelude::*; fn main() { let mut linear_seq = Sequence::new().transition_function(|_, i| i); let some_element = linear_seq.nth_element(111); println!("{some_element}"); }

여기서는 요소에 대한 불변 참조(이 경우 &usize )를 반환하는 nth_element() 메서드를 사용하여 111번째 요소에 액세스하고 있습니다.


linear_seq 변경 가능하게 만들었습니다. 그 이유는 nth_element() 메서드가 시퀀스의 활성 요소를 변경하기 때문입니다.


이러한 방식으로 시퀀스의 모든 요소에 액세스할 수 있습니다(인덱스가 0 인 요소부터 인덱스가 usize::MAX 인 요소까지).


Rust 반복자처럼 시퀀스를 반복할 수도 있습니다.

 use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new().transition_function(|_, i| i); linear_seq.for_each(|e| println!("{e}")); }


이 코드는 시퀀스의 모든 요소를 인쇄합니다(요소 0 부터 usize::MAX 요소까지).

 $ cargo run -q 0 1 2 3 4 5 6 7 8 9 10 11 12 13 ...


다음 코드를 사용하여 시퀀스에서 홀수 요소를 가져올 수 있습니다.

 use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new().transition_function(|_, i| i); let odd_elements = linear_seq.filter(|e| e % 2 != 0); odd_elements.for_each(|e| println!("{e}")); }


산출:

 $ cargo run -q 1 3 5 7 9 11 13 ...


우리가 정의하는 시퀀스는 게으르다. 즉, 필요하거나(반복의 경우) 명시적으로 요청하지 않는 한( nth_element() 메서드 사용) 요소가 생성되지 않는다는 의미입니다.

시퀀스의 일부 작업 :

때로는 시퀀스의 일부로만 작업해야 하는 경우도 있습니다. 이 경우에는 시퀀스 부분이 있습니다.


시퀀스 부분에는 세 가지 유형이 있습니다.

  • AliveElementsPart
  • ImmutableRangePart
  • MutableRangePart


AliveElements부분:

시퀀스에서 alive_elements() 메서드를 사용하여 라이브 요소를 가져올 수 있습니다.

 use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new() .transition_function(|_, i| i) .pre_generate(111); let alive_elements = linear_seq.alive_elements(); for alive_element in alive_elements { print!("{alive_element} "); } }

이 코드는 모든 활성 요소(이 경우 111개 요소를 미리 생성했기 때문에 0~110)를 인쇄합니다.


불변 범위 부분:

불변 범위는 살아있는 요소의 범위입니다. 시퀀스를 변경할 수 없습니다. 불변 범위를 생성하고 해당 요소 중 일부가 활성화되지 않은 경우 오류( DeadRange 오류)가 발생합니다.


Result 반환하는 range() 메서드를 사용하여 불변 범위를 만들 수 있습니다. Ok 변형은 ImmutableRangePart 이고 Err 변형은 RangeError 입니다. RangeErrorInvalidRange 변형(범위의 시작이 끝보다 큰 경우)이거나 DeadRange 변형(범위의 모든 요소가 살아 있지 않은 경우)일 수 있습니다.

 use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new().transition_function(|_, i| i); let range = linear_seq.range(0, 3).unwrap(); for e in range { println!("{e}") } }


이 코드는 살아있는 요소가 없기 때문에 DeadRange 오류로 인해 패닉이 발생합니다. 다음과 같이 이를 수정할 수 있습니다.

 use seqgen::prelude::*; fn main() { let mut linear_seq = Sequence::new().transition_function(|_, i| i); linear_seq.generate(3); let range = linear_seq.range(0, 3).unwrap(); for e in range { println!("{e}") } }

여기서는 범위를 유효하게 만들기 위해 3개의 요소를 생성했습니다.


가변 범위 부분:


변경 가능한 범위는 시퀀스를 변경(요소 생성)할 수 있습니다.


다음과 같이 변경 가능한 범위를 사용할 수 있습니다.

 use seqgen::prelude::*; fn main() { let mut linear_seq = Sequence::new().transition_function(|_, i| i); let mut_range = linear_seq.range_mut(0, 111).unwrap(); for e in mut_range { println!("{e}"); } }


이 코드는 0에서 110까지의 요소를 인쇄합니다.

아웃로덕션:

이 글을 끝까지 읽어주셔서 감사드리며, 이 글에서 유용한 내용을 찾으셨기를 바랍니다. 이 라이브러리를 개선할 수 있는 제안 사항이 있으면 GitHub에서 문제를 공개하고 , 라이브러리에 기여하고 싶다면 정말 좋을 것입니다.


여기에도 게시됨