数组
Tuple
tuple 函数可以创建一个固定大小的数组,等价 java 的类型为 Object [] :
## examples/tuple.avlet t = tuple(1, 2, "hello", 3.14);println("type of t: " + type(t));for x in t {println(x);}println("count of t: "+ count(t));println("t[0] = " + t[0]);t[0] = 100;println("t[0] = " + t[0]);
这个例子演示了 tuple 的基本操作: for 用来遍历数组, count 可以获取数组长度, t[x] 可以访问索引位置 x 的元素,同样也可以赋值特定位置的元素:
type of t: Object[]12hello3.14count of t: 4t[0] = 1t[0] = 100
tuple 可以放入任意类型的元素,如果要创建特定类型的,就需要用到其他函数。
创建类型数组并填充
可以通过 seq.array(type, ..args) 可以创建 type 类型的数组:
## examples/array.avlet a = seq.array(int, 1, 2, 3, 4);println("type(a) is : " + type(a));println("count(a) is: " + count(a));
比如上面创建了一个 int[] 数组,他的长度是 4,元素分别为 1, 2, 3, 4 。
如果传入错误的类型,创建将报错:
let a = seq.array(int, 1, 2, "hello", 4);
报错 Unexpected param type, expected: int, given: java.lang.String 。
但是如果可以转化为目标类型,比如 double 可以转成 int ,那么还是可以创建的:
let a = seq.array(int, 1, 2, 3.3, 4);map(a, println)
3.3 将被转为 3:
1234
seq.array 的 type 可以是基本类型,如 short 、 byte 、 char 、 bool 、 float 、 double 、 int 、 long 以及 void 。
也可以是对象,但是需要给完整的类名,比如创建字符串数组:
let s = seq.array(java.lang.String, "hello", "world", "aviator");println(string.join(s, ","));
string.join 函数将第一个参数的字符串集合用第二个参数的字符串起来,这里将输出 hello,world,aviator 。
创建空数组
如果要创建一个“空”数组,只确定类型和长度,可以用 seq.array_of(type, len) ,这样就创建了一个 type[len] 的数组,每个元素都将是该类型的默认值,比如整数就是 0,对象就是 null:
let a = seq.array_of(int, 3);println("type(a) is : " + type(a));println("count(a) is: " + count(a));println("before assignment:");for x in a {println(x);}for i in range(0, 3) {a[i] = i;}println("after assignment:");for x in a {println(x);}
输出:
type(a) is : int[]count(a) is: 3before assignment:000after assignment:012
创建多维数组
seq.array_of(Class, &dimensions) 也可以用于创建多维数组,举例来说:
## create multidimensional arraylet a = seq.array_of(long, 3, 2);assert(3 == count(a));assert(2 == count(a[0]));let x = 0;for i in range(0, 3) {for j in range(0, 2) {a[i][j] = x;x = x + 1;}}for i in range(0, 3) {for j in range(0, 2) {p("a[#{i}][#{j}] = #{a[i][j]}");}}
我们创建了一个 2 x 3 的二维数组,并遍历初始化,最终打印数组:
a[0][0] = 0a[0][1] = 1a[1][0] = 2a[1][1] = 3a[2][0] = 4a[2][1] = 5
遍历数组
上面其实已经演示了用 map 和 for 遍历数组的例子了,两者皆可,不过 map 将收集返回结果放入 collector 集合并返回,通常来说,如果你不需要结果,还是应当用 for 循环:
let a = seq.array(int, 1, 2, 3.3, 4);for x in a {println(x);}
集合 List, Map 和 Set
在 AviatorScript 中也可以创建 java 的各种常见集合类型,比如 java.util.List、java.util.Map 和 java.util.Set 等。我们将一一介绍。
创建 List
创建一个链表可以通过 seq.list 函数:
let list = seq.list(1, 2, 3);
上面将创建三个整数组成的 ArrayList 对象, seq.list 接受不定参数,如果不传入任何参数,创建的是一个空链表:
let empty_list = seq.list();
链表和数组类似,也可以通过 a[i] = x 的方式来赋值,前提是 i 落在长度内
## examples/list.avlet list = seq.list(1, 2, 3);list[0] = 4;list[1] = 5;list[2] = 6;println(list);
如果你尝试给长度范围之外的位置赋值,都将报错:
list[3] = 7;
报错:
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 3, Size: 3
因此你无法通过位置赋值的方式为一个空链表添加元素,我们将在后面操作集合里介绍添加元素的方式。
repeat 和 repeatedly
repeat(n, x) 函数用来创建一个全部是 x 的 List,并且个数为 n:
## examples/repeat.avlet list = repeat(10, "a");p("type of list: " + type(list));p("count of list: " + count(list));p("list[0]=" + list[0]);p("list is: " + list);
上面的例子将创建 10 个字符串 a 组成的链表:
type of list: java.util.ArrayListcount of list: 10list[0]=alist is: [a, a, a, a, a, a, a, a, a, a]
如果你有一个函数,可以产生元素,你想重复调用 n 次来产生一个集合,可以用 repeatedly(n, fn) :
let c = 0 ;let counter = lambda() ->c = c + 1;return c;end;let list = repeatedly(10, counter);p("type of list: " + type(list));p("count of list: " + count(list));p("list[0]=" + list[0]);p("list is: " + list);
我们创建了一个闭包函数 counter ,每次调用它会返回一个数字,并且数字从 1 开始递增,然后传入 repeatedly 调用 10 次,这就产生了一个 1~10 的数字集合:
type of list: java.util.ArrayListcount of list: 10list[0]=1list is: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
创建 Map
创建一个 HashMap 也很容易,使用 seq.map(k1, v1, k2, v2 ...) 的方式:
## examples/hash_map.avlet m = seq.map("a", 1, "b", 2, "c", 3, 4, 5);println(m);
key 并不要求类型一致,比如这里 key=4 ,对应的值是 5:
{a=1, b=2, c=3, 4=5}
seq.map 接受偶数个参数或者 0 个参数,不传入任何参数就是一个空的 map,可以通过 seq.put 来增加元素。
同样,对于 map ,你可以用 m.{key} 的方式来访问:
println("m.a = " + m.a);println("m.b = " + m.b);println("m.c = " + m.c);
但是如果你的 key 不是合法的变量,就不能用这样的方式访问了,需要用到 seq.get 函数:
println("m.4 = " + seq.get(m, 4));
可以赋值:
m.a = 100;println("m.a = " + m.a);
但是,如果 key 不是合法变量,就需要用到 seq.put 函数:
seq.put(m, 4, 99);println("m.4 = " + seq.get(m, 4));
为什么不是 _seq.set_ 呢? 因为 _seq.set_ 是用于创建集合 set 的。
从 5.2 开始,可以使用类似数组的语法 **map[key]** 来获取和设置值:
m["a"] = 'aviator';println("m['a'] = " + m['a']);
<br />
key 和 value 集合
如果要获取 key 的集合,可以用 seq.keys(m) 函数, value 集合是用 seq.vals 函数:
p("key set: " + seq.keys(m));p("value set: " + seq.vals(m));
输出:
key set: [a, b, c, 4]value set: [aviator, 2, 3, 99]
创建 Set
创建不重复的元素组成的集合 Set,可以用 seq.set :
## examples/hash_set.avlet s = seq.set(1, 2, 2, "hello", 3.3, "hello");println(s);println("type(s) is: " + type(s));
输出:
[1, 2, hello, 3.3]type(s) is: java.util.HashSet
我们传入的参数有重复的 2 和字符串 hello,但是最终结果是一个去重的集合 java.util.HashSet 。
Set 最常见的操作是判断某个元素是否存在,可以用 include 函数:
println(include(s, 1));println(include(s, "hello"));println(include(s, 100));
输出:
truetruefalse
操作集合
这里我们介绍操作这些集合类的通用操作,首先是添加元素。
添加元素 seq.add
往集合里添加元素可以用上面介绍过的 seq.add(coll, element) ,它支持 List/Set ,同时他有一个三参数版本 seq.add(coll, key, value) 可以用于添加键值对到 map:
## examples/collections.avlet list = seq.list();let set = seq.set();let map = seq.map();## add elementsfor i in range(0, 3) {seq.add(list, i);seq.add(set, i);seq.add(map, i, i);}println("list: " + list);println("set: " + set);println("map: " + map);
输出:
list: [0, 1, 2]set: [0, 1, 2]map: {0=0, 1=1, 2=2}
如果你的元素类型是 Map.Entry ,也可以直接调用 seq.add(m, e) 来添加:
seq.add(map, seq.entry(i, i));
seq.entry(key, value) 用于创建一个 Map.Entry 对象。
访问元素 seq.get
访问集合中的元素可以用 seq.get(coll, key) 函数,它同时支持数组和所有集合类型:
- 对于数组和链表, key 就是
0~(len - 1)的索引位置整数,返回的是该位置的值,超过范围内的访问将抛出异常。 - 对于 map 来说,key 就是键值对的 key,返回的是对应的 value。
- 对于 set 来说,key 就是集合里的元素,如果存在,返回该 key 本身,不存在返回 nil。
## retrieve elements by seq.getfor i in range(0, 3) {assert(i == seq.get(list, i));assert(i == seq.get(set, i));assert(i == seq.get(map, i));}println("seq.get(set, 3) is: " + seq.get(set, 3)); ## nil
这里我们用了 assert 函数,它接受一个布尔值,如果为 false 将抛出 AssertFailed 异常。
判断元素是否存在
对于数组、List 和 Set 来说,判断某个元素是否存在都应该用 include(coll, element) 函数,对于数组和 List 来说,这个函数的时间复杂度是 O(n),因为要遍历整个数组或链表;对于 Set 来说是 O(1) 时间复杂度,直接调用用了 Set#contains 方法。
for i in range(0, 3) {assert(include(list, i));assert(include(set, i));}assert(!include(list, 5));assert(!include(set, 5));
对于 map 来说,如果是判断 key 是否存在,需要用 seq.contains_key(coll, key) :
for i in range(0, 3) {assert(seq.contains_key(map, i));}assert(!seq.contains_key(map, 5));
如果是判断 Map.Entry 是否存在,仍然继续使用 include :
for i in range(0, 3) {assert(include(map, seq.entry(i, i)));}
遍历集合
遍历集合和数组的方式一样,同样通过 for..in 语句:
## Iterate the collection by for..in loopprintln("list elements:");for x in list {println(x);}println("set elements:");for x in set {println(x);}println("map elements:");for x in map {println(x.key + "=" + x.value);}
对于 map 来说迭代循环中的元素就是 Map.Entry 对象,可以通过 key 和 value 属性来访问键和值。
输出:
list elements:012set elements:012map elements:0=01=12=2
删除元素 seq.remove
删除元素也是常见的需求,可以用 seq.remove(coll, element) ,对于 List/Set 和 Map 都是如此,如果是 Map,传入的应该是 key:
## remove elementsassert(list == seq.remove(list, 2));assert(list == seq.remove(list, 4));assert(set == seq.remove(set, 1));assert(map == seq.remove(map, 0));println("list: " + list);println("set: " + set);println("map: " + map);
打印:
list: [0, 1]set: [0, 2]map: {1=1, 2=2}
可见删除生效了,删除不存在的元素不产生影响。 seq.remove 返回的是删除后的集合对象。
