将 Iterator<(A,B)> 拆分为 Iterator 和 Iterator

2023-12-25

我想分割实现的对象的输出Iterator<(A,B)>分成两个实现的对象Iterator<A> and Iterator<B>。由于其中一个输出的迭代次数可能多于另一个,因此我需要缓冲Iterator<(A,B)>(因为我不能依赖Iterator<(A,B)>可克隆。)问题是迭代器可能是无限的,所以我不能简单地将迭代器的输出收集到两个缓冲区中并在两个缓冲区上返回迭代器。

所以看来我需要保存缓冲区A and B对象,每当其中一个缓冲区为空时,我都会用来自Iterator<(A,B)>目的。这意味着我需要两个可迭代结构,它们具有对输入迭代器的可变引用(因为它们都需要调用next()在输入上填充缓冲区),这是不可能的。

那么,有没有什么方法可以安全地实现这一点呢?


这个有可能。正如您所确定的,您需要从两个句柄对基本迭代器进行可变引用,这可以使用具有“内部可变性”的类型 http://doc.rust-lang.org/master/std/cell/,即使用unsafe内部代码公开一个安全的API来获取&mut可别名数据(即包含在&)通过动态强制编译器通常在外部编译时强制执行的不变量unsafe.

I'm assuming you're happy to keep the two iterators on a single thread1, so, in this case, we want a RefCell http://doc.rust-lang.org/std/cell/struct.RefCell.html. We also need to be able to have access to the RefCell from the two handles, entailing storing either a &RefCell<...> or an Rc<RefCell<...>>. The former would be too restrictive, as it would only allow us to use the pair of iterators in and below the stack frame in which the RefCell is created, while we want to be able to freely pass the iterators around, so Rc http://doc.rust-lang.org/std/rc/index.html it is.

总之,我们基本上将存储一个Rc<RefCell<Iterator<(A,B)>>>,这只是缓冲的问题。适合这里工作的工具是RingBuf http://doc.rust-lang.org/std/collections/struct.RingBuf.html因为我们希望在前面和后面进行有效的推/弹出操作。因此,我们正在共享的东西(即在RefCell)可能看起来像:

struct SharedInner<A, B, It> {
    iter: It,
    first: RingBuf<A>,
    second: RingBuf<B>,
}

我们可以将实际共享的类型缩写为type Shared<A, B, It> = Rc<RefCell<SharedInner<A, B, It>>>;,它允许我们定义迭代器:

struct First<A, B, It> {
    data: Shared<A, B, It>
}
impl Iterator<A> for First<A,B,It> {
    fn next(&mut self) -> Option<A> {
        // ...
    }
}

实施next首先要做的是得到一个&mut to the SharedInner, via self.data.borrow_mut();。然后从中获取一个元素:检查正确的缓冲区,或者从其中获取一个新元素iter(记得缓冲剩余的B):

let mut inner = self.data.borrow_mut();

inner.first.pop_front().or_else(|| {
    inner.iter.next().map(|(a,b)| {
        inner.second.push(b);
        a
    })
})

Docs: RingBuf.pop_front http://doc.rust-lang.org/std/collections/struct.RingBuf.html#method.pop_front, Option.or_else http://doc.rust-lang.org/core/option/type.Option.html#method.or_else.

另一侧的迭代器类似。总共:

use std::cell::RefCell;
use std::collections::{Deque, RingBuf};
use std::rc::Rc;

struct SharedInner<A, B, It> {
    iter: It,
    first: RingBuf<A>,
    second: RingBuf<B>
}

type Shared<A, B, It> = Rc<RefCell<SharedInner<A, B, It>>>;

struct First<A, B, It> {
    data: Shared<A, B, It>
}

impl<A,B, It: Iterator<(A,B)>> Iterator<A> for First<A, B, It> {
    fn next(&mut self) -> Option<A> {
        let mut inner = self.data.borrow_mut();

        // try to get one from the stored data
        inner.first.pop_front().or_else(|| 
            // nothing stored, we need a new element.
            inner.iter.next().map(|(a, b)| {
                inner.second.push(b);
                a
            }))
    }
}

struct Second<A, B, It> {
    data: Shared<A, B, It>
}
impl<A,B, It: Iterator<(A,B)>> Iterator<B> for Second<A,B,It> {
    fn next(&mut self) -> Option<B> {
        let mut inner = self.data.borrow_mut();

        inner.second.pop_front().or_else(|| {
            inner.iter.next().map(|(a, b)| {
                inner.first.push(a);
                b
            })
        })
    }
}

fn split<A, B, It: Iterator<(A,B)>>(it: It) -> (First<A, B, It>, 
                                                Second<A, B, It>) {
    let data = Rc::new(RefCell::new(SharedInner { 
        iter: it,
        first: RingBuf::new(),
        second: RingBuf::new(),
    }));

    (First { data: data.clone() }, Second { data: data })
}

fn main() {
    let pairs = range(1u32, 10 + 1).map(|x| (x, 1.0 / x as f64));

    let (mut first, mut second) = split(pairs);

    println!("first:");
    for x in first.by_ref().take(3) {
        println!("  {}", x);
    }

    println!("second:");
    for y in second.by_ref().take(5) {
        if y < 0.2 { break }
        println!("  {}", y);
    }

    let a = first.collect::<Vec<u32>>();
    let b = second.collect::<Vec<f64>>();

    println!("a {}\nb {}", a, b);
}

打印

first:
  1
  2
  3
second:
  1
  0.5
  0.333333
  0.25
  0.2
a [4, 5, 6, 7, 8, 9, 10]
b [0.166667, 0.142857, 0.125, 0.111111, 0.1]

playpen http://is.gd/U1qj6n.

有多种方法可以对此进行优化,例如取入时First,仅缓冲剩余的B if a Second句柄存在。

1 If you were looking to run them in separate threads just replace the RefCell with a Mutex http://doc.rust-lang.org/std/sync/struct.Mutex.html and the Rc with an Arc http://doc.rust-lang.org/std/sync/struct.Arc.html, and add the necessary bounds.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将 Iterator<(A,B)> 拆分为 Iterator 和 Iterator 的相关文章

随机推荐

  • PHPExcel - 克隆工作表并保持其原始样式

    我尝试在此处和 PHPExcel 官方文档 论坛中检查所有可能的类似解决方案 但我没有找到任何解决我的问题的方法 问题 我试图clone 或者诚实地说 复制 一张表将其解析为通过 phpexcel 创建的另一个文件保持克隆工作表的样式 设置
  • 验证 CRC 校验和是否为零

    我过去接触过 CRC 16 校验和 习惯于通过对我要验证的文件重新计算 CRC 16 校验和 加上 CRC 16 本身的 2 个字节来验证它 如果结果为零 则文件完整性有效 否则无效 这可以非常有效地编码 就像下面的伪 C 一样 if re
  • 如何使用 ARM64 执行多项式乘法?

    Microsoft 最近发布了 ARM64 构建工具 作为 Visual Studio 15 9 的一部分 我正在完成 ARM64 的移植 我在多项式乘法方面遇到麻烦 我遇到的问题是 微软没有提供预期的数据类型 例如poly64 t 或者像
  • 不使用 cfqueryparam 防止 SQL 注入

    我有包含很多未使用的查询的旧项目cfqueryparam以防止SQL注入 有没有办法使用某些函数在每个表单字段的应用程序级别上执行类似的操作 作为具有 PHP 背景的初学者 我认为我可以循环发布的数据并执行escape string 或类似
  • 如何静默安装 UWP appx?

    我开发了一个UWP appx 它可以在cmd exe提示符下安装 C test gt myapp appx 但安装过程中会弹出一个 Windows GUI 有什么方法吗 使用静默参数安装它 如下所示 C test gt myapp appx
  • 表格列格式

    我正在尝试格式化一列 table table 用一个
  • 解析 HTML:Python 中的 lxml 错误

    我正在编写一个简单的脚本来从中获取大灰色表here http www afi com 100years movies10 aspx 我的代码如下 import urllib2 from lxml import etree html urll
  • Jquery,使用 json 自动完成,id 与显示值

    我有一个复杂的自动完成问题 这是我正在开发的网站的消息系统 我希望它能够在您输入用户名的地方工作 它会返回用户的图像 姓名和 ID 的缩略图 然后 当您选择它时 我希望它显示用户名 但当它发回时 我希望它发回他们的 ID 因为用户名不是唯一
  • PHP文件加密方法。存在简单的东西吗?

    似乎没有任何令人愉快的方法来加密 php 中的文件 php 的内置方法 mcrypt 不太可移植 因为大多数服务器不支持它们 命令行加密工具就像丑陋的黑客 对字符串进行加密这很好 但如果我们想加密一个文件 它并没有多大帮助 特别是对其他人解
  • 将对话框保持在窗口顶部,但不是在所有内容之上

    在我的 WPF 应用程序中 我有很多弹出的自定义对话框 以便用户可以使用以下命令执行各种操作someDialogClass ShowDialog 为了确保对话框位于调用它的窗口顶部 我添加Topmost True to the Window
  • 实体框架中使用 OR 条件的动态查询

    我正在创建一个应用程序来搜索数据库并允许用户动态添加任何条件 大约 50 个可能的条件 就像下面的问题一样 使用实体框架创建动态查询 https stackoverflow com q 5541234 810850 我目前正在进行一项检查每
  • 焦点事件发生变化?

    我正在将 Visual Basic 6 程序移植到 PyQt 我需要调用一个函数来设置某些小部件始终启用 禁用 我不想调用一个函数太多次 所以我发现了一个事件 当焦点从一个小部件更改为另一个小部件时 我可以调用我的小部件管理器功能 我正在
  • 在Python中的一个图中叠加热图

    我有两个 100x100 矩阵 u 0 and u 1 我已将两个数组的值设置在 0 和 1 之间 以使用 matplotlib 函数制作热图pcolormesh 我可以使用以下方法获得一张热图 fig1 plt pcolormesh u
  • 使用 loc 时的 Pandas SettingWithCopyWarning [重复]

    这个问题在这里已经有答案了 关于使用 loc 进行索引 切片分配的一般问题 假设以下数据帧 df df A B C 0 a b 1 a b 2 b a 3 c c 4 c a 重现代码 df pd DataFrame A list aabc
  • 如何在 SQL Server 中转置查询结果(行到列)

    我的查询给出的结果如下 所以 我想将结果转换成这样 请注意带有 NULL 值的交叉字段 PIVOT 是实现这一目标的方法 一开始它可能会令人困惑 至少对我来说是这样 https www codeproject com Tips 500811
  • 使用 PHP cURL 进行缓存

    我正在使用 PHP cURL 从另一个网站获取信息并将其插入到我的页面中 我想知道是否可以将获取的信息缓存在我的服务器上 例如 当访问者请求某个页面时 系统会获取该信息并在我的服务器上缓存 24 小时 然后 该页面将完全在本地提供 24 小
  • 在虚拟环境中将包安装到全局站点包中

    让我先声明我已阅读过pip 安装在全局站点包中而不是 virtualenv https stackoverflow com questions 20952797 pip installing in global site packages
  • PySpark - 按列的值拆分/过滤 DataFrame

    我有一个与此示例类似的 DataFrame Timestamp Word Count 30 12 2015 example 1 3 29 12 2015 example 2 1 28 12 2015 example 2 9 27 12 20
  • 跨 docker 容器共享内存

    如果使用 Java MQ 类 而不是 JTA 将 Websphere MQ 用作 XA 分布式事务 事务管理器 则 Java 应用程序和 WMQ 都需要驻留在同一主机上 有人告诉我这是因为共享内存被用作进程间通信机制 Java 应用程序和
  • 将 Iterator<(A,B)> 拆分为 Iterator 和 Iterator

    我想分割实现的对象的输出Iterator lt A B gt 分成两个实现的对象Iterator a and Iterator b 由于其中一个输出的迭代次数可能多于另一个 因此我需要缓冲Iterator lt A B gt 因为我不能依赖
Powered by Hwhale