paint-brush
SeqGen:我为序列生成创建的库by@crazyrat
530
530

SeqGen:我为序列生成创建的库

crazyrat7m2023/12/15
Read on Terminal Reader

序列(非正式地讲)是一组元素(主要是数字),其中每个元素的产生都基于前面的元素。 最基本的例子是一个简单的正整数线性序列,其中第一个元素是 0,下一个元素是前一个元素加一,因此我们可以通过将第一个元素加 1 来得到第二个元素,然后我们可以得到第三个元素元素通过将一个添加到第二个元素,依此类推。线性序列如下所示:{0, 1, 2, 3, …, n}。
featured image - SeqGen:我为序列生成创建的库
crazyrat HackerNoon profile picture

介绍:

如果您在互联网上搜索可以生成序列的库,您几乎找不到,尽管序列是离散数学和计算机科学的核心概念。


在这篇短文中,我们将介绍我为序列生成编写的一个名为SeqGen的库。

什么是序列?

序列(非正式地讲)是一组元素(主要是数字),其中每个元素的产生都基于前面的元素。


最基本的例子是一个简单的正整数线性序列,其中第一个元素是 0,下一个元素是前一个元素加一,因此我们可以通过将第一个元素加一来得到第二个元素,然后我们可以得到第三个元素元素通过将一个添加到第二个元素,依此类推。线性序列如下所示: {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溢出。更好的定义是使用 big int 而不是u128

使用序列

定义序列后,我们可以访问它的元素:

 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}"); }

在这里,我们使用nth_element()方法访问第 111 个元素,该方法返回对该元素的不可变引用(在本例中为&usize )。


请注意,我们使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


活着的元素部分:

我们可以使用序列上的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} "); } }

此代码将打印所有活动元素(在本例中为 0 到 110,因为我们预先生成了 111 个元素)。


不可变范围部分:

不可变范围是活动元素的范围;他们不能改变序列。如果您将创建一个不可变范围并且并非所有元素都处于活动状态,您将收到错误( DeadRange错误)。


我们可以使用返回Resultrange()方法创建一个不可变范围。 Ok变体是ImmutableRangePartErr变体是RangeErrorRangeError可能是InvalidRange变体(如果范围的开头大于其结尾),也可能是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 上打开一个问题,如果你想为这个库做出贡献,那就太好了。


也发布在这里