D语言标准库之range序列集

     D语言标准库中是这么解释Range的:

     Ranges generalize the concept of arrays,lists, or anything that involves sequential access

     意思是Range概括的数组,列表,或任何涉及顺序访问的概念,我们就叫它序列集吧,以区分aggregate(迭代集)与sets(键值集)。

     包文件range.d

一、chain函数

     把几个序列集连接到成一个序列集.

import std.stdio;
import std.range;
int main(string[] argv)
{
    int[] a = [1,2,3];
    int[] b = [4,5,6];
    auto c = chain(a , b);
    writeln("c len:",c.length);
    writeln("c:",c);
    writeln("c type is:",typeid(c));
    writeln("c[0]:",c[0]);
    writeln("c[3]:",c[3]);
    writeln("Items List:");
    foreach(i;c)
    {
        writeln(i);
    }
    readln();
    return 0;
}

image

从运行结果来看,chain是把两个数组连接为一个对象,类型为std.range.chain(int[],int[]).chain.Result类型。

对这个单一的对象可以使用foreach操作来处理。也可以使用索引来访问,很不错的东西,看起来好像比C#里的IEnumerable功能多点,但IEnumerable的抽象更高一些,没有要求顺序访问和元素数量,只要求能迭代,可能aggregate是指的这个概念。

       IEnumerable只要求能枚举元素,这一点很重要,因为很多时候,不能要求数据都在内存中,比如对数据库记录的访问,数据很可能并不在内存中,如果有了数量的要求,那么也就使得Range不能很好的处理数据库数据访问问题。

      因此,Range只能叫做序列集,而不能称为枚举集,或是迭代集。而序列集应该也是属于迭代集的一种,既然Range是迭代集的一种,那么他是怎么实现让foreach访问的呢? 值得研究的一个问题,下来看一下序列集的基本操作

     

二、序列集的基本操作 

       Result类型常用的几个属性与函数

      1)empty 返回序列集是否为空

      2)front与popFront函数

import std.stdio;
import std.range;
int main(string[] argv)
{
    int[] a = [0,1,2];
    int[] b = [4,5,6];
    auto c = chain(a , b);
    writeln("c len:",c.length);
    for(int i=0;i< c.length ;i++)
    {
        auto tmp = c.front();
        writeln("c front:",tmp);
        c.popFront();
    }
    writeln("c len end:",c.length);
    readln();
    return 0;
}

image

怎么不是6个呢,是range出bug了吗? 当然不是了,修改一下代码再来看看:

import std.stdio;
import std.range;
int main(string[] argv)
{
    int[] a = [0,1,2];
    int[] b = [4,5,6];
    auto c = chain(a , b);
    writeln("c len:",c.length);
    auto len = c.length;
    for(int i=0;i< len ;i++)
    {
        auto tmp = c.front();
        writeln("c front:",tmp);
        c.popFront();
    }
    writeln("c len end:",c.length);
    readln();
    return 0;
}

image 运行正确了,原因for的时候到第4次的时候c.length为3,i也为3所以循环结果了。

      3)back 与 popBack  取最后一个数据,弹出最后一个数据。 与front用法相似。

      4)opIndex,opIndexAssign,opSlice函数 用于操作符重载

         moveAt,moveFront,moveBack是做什么的,后来才搞明白是用于实现元素的移动

三:几个Range类型的判断 与 元素类型操作

      1) isInputRange      InputRange类型判断

      2) isOutputRange    OutputRange类型判断

      3) isForwardRange   ForwardRange类型判断

      4) isBidirectionalRange    BidirectionalRange类型判断

      5) isRandomAccessRange   RandomAccessRange类型判断

      6) hasMobileElements    元素是否支持移动操作

      7) ElementType  取元素的类型

      8) ElementEncodingType  取元素编码类型元素类型

      9) hasSwappableElements  

     10) hasAssignableElements

     11) hasLvalueElements

     12) hasLength

     13) isInfinite

     14) hasSlicing

static struct S
{
    this(this) @disable;
}
static assert(is(ElementType!(S[]) == S));
struct E { ushort id; }
struct R
{
    E front() { return E.init; }
}
static assert(is(ElementType!R == E));

       15) SortedRange   用于排序的序列集

三:put函数  实现InputRange的操作

import std.stdio;
import std.range;
int main(string[] argv)
{

    void myprint(in char[] s) { writeln("S:" , s); }
    auto r = &myprint;
    put(r, "Test put in function");
    readln();
    return 0;
}

image

用于对函数参数的输入和调用。这在对range使用lambda表达式是个很有用的东西。下面是对委托的支持,运行结果同上:

import std.stdio;
import std.range;
int main(string[] argv)
{
    auto f = delegate (const(char)[] s) {writeln("S:" , s);};
    put(f, "Test put in function");
    readln();
    return 0;
}

 

 

再回到序列集上来,这才是重点

       从第一个集合操作函数 chain函数 后,看了一些相关的实现。下面再回到操作函数上来。

1.  chain函数

      把多个序列集连接成一个序列集。

2、roundRobin 函数

将两个序列集交叉成一个序列集:

import std.stdio;
import std.range;
int main(string[] argv)
{
    int[] a = [ 1, 2, 3 ];
    int[] b = [ 10, 20, 30, 40 ];
    auto r = roundRobin(a, b);
    writeln(r);
    readln();
    return 0;
}

image 

3、radial 函数

      把序列集做星形排列

import std.stdio;
import std.range;
int main(string[] argv)
{
    int[] a = [ 1, 2, 3, 4, 5 ,6,7,8];
    auto r = radial(a);
    writeln(r);
    readln();
    return 0;
}
image

4、take 函数

     从开始位置取N个元素

import std.stdio;
import std.range;
int main(string[] argv)
{
    int[] a = [ 1, 2, 3, 4, 5 ,6,7,8];
    auto r = take(a,5);
    writeln(r);
    readln();
    return 0;
}

image

5. takeExactly函数

    与take取的序列正好相反。

6.takeOne

    只取一个

import std.stdio;
import std.range;
int main(string[] argv)
{
    int[] a = [ 1, 2, 3, 4, 5 ,6,7,8];
    auto r = a.takeOne();
    writeln(r);
    readln();
    return 0;
}

image

7.takeNone

    一个都不取

import std.stdio;
import std.range;
int main(string[] argv)
{
    int[] a = [ 1, 2, 3, 4, 5 ,6,7,8];
    auto r = a.takeNone();
    writeln(r);
    readln();
    return 0;
}

image

8.drop

     去掉N个元素,与C#中的skip一样

import std.stdio;
import std.range;
int main(string[] argv)
{
    int[] a = [ 1, 2, 3, 4, 5 ,6,7,8];
    auto r = a.drop(3);
    writeln(r);
    readln();
    return 0;
}

image

9.dropBack

   去掉最后的N个元素

import std.stdio;
import std.range;
int main(string[] argv)
{
    int[] a = [ 1, 2, 3, 4, 5 ,6,7,8];
    auto r = a.dropBack(3);
    writeln(r);
    readln();
    return 0;
}

image 

10.dropExactly

      好像与drop一样,不明白

11.dropBackExactly

     好像与dropBack一样,不明白

12.dropOne

    只去掉第一个元素

13.dropBackOne

    只去掉最后一个元素

14.popFrontN

    弹出前来个元素,与drop不同,drop不会改变a,后popFrontN直接操作变量a。

import std.stdio;
import std.range;
int main(string[] argv)
{
    int[] a = [ 1, 2, 3, 4, 5 ,6,7,8];
    a.popFrontN(3);
    writeln(a);
    readln();
    return 0;
}

image

15.popBackN

     弹出最后的N个元素。

16.popFrontExactly

     与popFrontN效果一样,不知道什么原因

17.popBackExactly

     …

18.repeat

    重复生成N个元素

import std.stdio;
import std.range;
int main(string[] argv)
{
    auto a = repeat(3,10);
    writeln(a);
    readln();
    return 0;
}

image

19.cycle

    回环序列集,使用foreach访问会无限循环

import std.stdio;
import std.range;
int main(string[] argv)
{
    int[] nums = [1,2,3];
    auto c2 = cycle(nums);
    writeln(c2);
    readln();
    return 0;
}

image

writeln(c2)会访问每一个元素,使得出现无限循环。 使用take和drop访问或取元素。例:

import std.stdio;
import std.range;
int main(string[] argv)
{
    int[] nums = [1,2,3];
    auto c2 = cycle(nums);
    auto n3_5 = c2.drop(3).take(5);
    writeln(n3_5);
    readln();
    return 0;
}

image

20.zip

    没搞明白是干什么的

21.lockstep

22.recurrence

     递归序列生成函数

import std.stdio;
import std.range;
int main(string[] argv)
{
    auto fact = recurrence!("n * a[n-1]")(2).take(10);
    writeln(fact);
    readln();
    return 0;
}

image

import std.stdio;
import std.range;
int main(string[] argv)
{
    auto fact = recurrence!"a[n-2]"(1, 2).take(10);
    writeln(fact);
    readln();
    return 0;
}

image

23.sequence

   按公式生成序列集,这是一个非常有用的函数。

import std.stdio;
import std.range;
int main(string[] argv)
{
    auto odds = sequence!("a[0] + n * a[1]")(0,2);
    auto tmp = odds.take(10);
    writeln(tmp);
    readln();
    return 0;
}

image 有两个约定参数a与n。

a为传入参数数组,a[0]指的是a的第一个元素,在上程序中为0 ,a[1]指的是a的第二个元素,在上程序中为2。

n为序列集的索引号,即为0,1,2……,就是for(int n=0;n< 无限大;n++)

24.iota

    生成阶梯序列集

import std.stdio;
import std.range;
int main(string[] argv)
{
    auto r = iota(0, 20, 2);
    writeln(r);
    readln();
    return 0;
}

image 第一个参数为开始的数

第二个参数为结束的数

第三个参数为步数,也是间隔数

25.frontTransversal

    取矩阵竖向序列集,仅仅是第一列

26.transversal

取矩阵竖向序列集

import std.stdio;
import std.range;
int main(string[] argv)
{
    int[][] x = new int[][2];
    x[0] = [1, 2];
    x[1] = [3, 4];
    auto col0 = transversal(x, 0);
    auto col1 = transversal(x, 1);
    writeln(col0);
    writeln(col1);
    readln();
    return 0;
}

image

27.transposed

     D语言中的转轶函数

import std.stdio;
import std.range;
int main(string[] argv)
{
    int[][] x = new int[][2];
    x[0] = [1, 2];
    x[1] = [3, 4];
    auto tr = transposed(x);
    writeln(tr);
    readln();
    return 0;
}
image

28,indexed

    使用索引序列取元素

import std.stdio;
import std.range;
int main(string[] argv)
{
    auto source = [1, 2, 3, 4, 5];
    auto indices = [4, 3, 1, 2, 0, 4];
    auto ind = indexed(source, indices);
    writeln(ind);
    readln();
    return 0;
}

image indices为索引序列,显示出来是使用indices为索引在source中取出来的元素。

29.chunks

      把一个序列集按块大小进行分隔,生成多一维的序列集

import std.stdio;
import std.range;
int main(string[] argv)
{
    auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    auto chunks = chunks(source, 4);
    writeln(chunks);
    readln();
    return 0;
}

image      来一个综合使用的例子:

import std.stdio;
import std.range;
int main(string[] argv)
{
    auto arr = [1,2,3,4];
    auto tmp = arr.cycle().chunks(4).take(4);
    writeln(tmp);
    readln();
    return 0;
}

image     太神奇了,这么强的能力!!  ~~~~

30.only

import std.stdio;
import std.range;
int main(string[] argv)
{
    auto r = only("one", "two", "three").joiner(" ");
    writeln(r);
    readln();
    return 0;
}

     image

31.assumeSorted

      用于生成SortedRange集合,该集合可用于做排序等操作。

      这个SortedRange的东西也不少。

import std.stdio;
import std.range;
int main(string[] argv)
{
    int[] arr = [ 1, 5, 3, 2, 5, 6, 7, 8, 9, 10 ];
    auto s1 = arr.assumeSorted();
    writeln(s1);
    readln();
    return 0;
}

image

只是转换类型,不会进行排序操作

32.RefRange

     RefRange是引用集合

33.contains   是否包含元素

     SortedRange类型的内部函数,要先转为SortedRange后才能使用

import std.stdio;
import std.range;
int main(string[] argv)
{
    int[] arr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
    auto s1 = arr.assumeSorted().contains(2);
    auto s2 = arr.assumeSorted().contains(32);
    writeln(s1);
    writeln(s2);
    readln();
    return 0;
}

image 

34.walkLength

35.swap

     把元素转换

import std.stdio;
import std.range;
int main(string[] argv)
{
    auto a = [ 1, 2, 3, 42, 52, 64 ];
    swap(a[3], a[5]);
    writeln(a);
    readln();
    return 0;
}

     image

36.trisect

     SortedRange类型的内部函数

37.lowerBound

39.refRange

39.retro

序列返向操作

import std.stdio;
import std.range;
int main(string[] argv)
{
    int[] a = [ 1, 2, 3, 4, 5 ];
    auto r = a.retro();
    writeln(r);
    readln();
    return 0;
}

image

40.stride

     按步子来取间隔元素生成新的序列

import std.stdio;
import std.range;
int main(string[] argv)
{
    int[] arr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
    auto s1 = stride(arr, 1);
    auto s2 = stride(arr, 2);
    auto s3 = stride(arr, 3);
    writeln(s1);
    writeln(s2);
    writeln(s3);
    readln();
    return 0;
}

image

41.appender      数组中的array.d  array的操作可能还有很多需要再看看

import std.stdio;
import std.range;
int main(string[] argv)
{
    int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
    auto s = arr1.drop(3).take(3).filter!(a => a < 5);
    writeln(s);
    readln();
    return 0;
}

D中drop相当于C#中的skip

filter相当于where

原文地址:https://www.cnblogs.com/wanhongnan/p/5726727.html