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;
}
从运行结果来看,chain是把两个数组连接为一个对象,类型为std.range.chain(int[],int[]).chain.Result类型。
对这个单一的对象可以使用foreach操作来处理。也可以使用索引来访问,很不错的东西,看起来好像比C#里的IEnumerable功能多点,但IEnumerable的抽象更高一些,没有要求顺序访问和元素数量,只要求能迭代,可能aggregate是指的这个概念。
IEnumerable只要求能枚举元素,这一点很重要,因为很多时候,不能要求数据都在内存中,比如对数据库记录的访问,数据很可能并不在内存中,如果有了数量的要求,那么也就使得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;
}
怎么不是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;
}
运行正确了,原因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;
}
用于对函数参数的输入和调用。这在对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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
第二个参数为结束的数
第三个参数为步数,也是间隔数
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;
}
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;
}
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;
}
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;
}
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;
}
30.only
import std.stdio;
import std.range;
int main(string[] argv)
{
auto r = only("one", "two", "three").joiner(" ");
writeln(r);
readln();
return 0;
}
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;
}
只是转换类型,不会进行排序操作
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;
}
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;
}
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;
}
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;
}
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