首页 > 解决方案 > 可变参数的解构迭代,如 D 中的元组序列

问题描述

假设我想处理一个可变参数函数,该函数交替传递 1 个或多个间隔的开始值和结束值,并且它应该在这些间隔中返回一系列随机值。你可以想象输入是一个扁平的元组序列,所有元组元素都分布在一个范围内。

import std.meta; //variadic template predicates
import std.traits : isFloatingPoint;
import std.range;

auto randomIntervals(T = U[0], U...)(U intervals)
if (U.length/2 > 0 && isFloatingPoint!T && NoDuplicates!U.length == 1) {
    import std.random : uniform01;
    
    T[U.length/2] randomValues;
    // split and iterate over subranges of size 2
    foreach(i, T start, T end; intervals.chunks(2)) {   //= intervals.slide(2,2)
        randomValues[i] = uniform01 * (end - start) + start,
    }
    return randomValues.dup;
}

例子不重要,我只是用来解释。块大小可以是任何有限的正数size_t,不仅2并且更改块大小只需要更改 foreach 循环中的循环变量的数量。

在上面的这种形式中,它不会编译,因为它只期望 foreach 循环有一个参数(一个范围)。我想要的是自动使用或推断滑动窗口作为元组的东西,从给定循环变量的数量派生,并用范围/数组的下一个元素填充附加变量+允许附加索引,可选。根据文档,元组范围允许将元组元素解构为foreach -loop-variables,因此我想到的第一件事是将范围转换为元组序列,但没有找到方便的功能为了这。

有没有一种简单的方法可以将解构的子范围(如我的示例代码中所示的简单)与索引一起循环?或者是否有一个(标准库)函数可以将范围拆分为相同大小的枚举元组?如何轻松地将子范围的范围变成元组的范围?

在这种情况下是否有可能std.algorithm.iteration.map(编辑:使用简单的函数参数来映射并且不访问元组元素)?

编辑:我想忽略不适合整个元组的最后一个块。它只是没有迭代。

编辑:这不是我自己无法编程,我只希望有一个简单的符号,因为这种循环多个元素的用例非常有用。如果在 D 中有类似 JavaScript 中的“spread”或“rest”运算符,请告诉我!

谢谢你。

标签: foreachtuplesdvariadic

解决方案


chunksslide返回Ranges,而不是元组。它们的最后一个元素可以包含小于指定大小,而元组具有固定的编译时间大小。

如果您需要解构,则必须实现自己的返回元组的块/幻灯片。要向元组显式添加索引,请使用enumerate. 这是一个例子:

import std.typecons, std.stdio, std.range;

Tuple!(int, int)[] pairs(){
    return [
        tuple(1, 3),
        tuple(2, 4),
        tuple(3, 5)
    ];
}

void main(){
    foreach(size_t i, int start, int end; pairs.enumerate){
        writeln(i, ' ', start, ' ', end);
    }
}

编辑:

正如 BioTronic 所说,使用map也是可能的:

foreach(i, start, end; intervals
                       .chunks(2)
                       .map!(a => tuple(a[0], a[1]))
                       .enumerate){

推荐阅读