数组

Tuple

tuple 函数可以创建一个固定大小的数组,等价 java 的类型为 Object []

  1. ## examples/tuple.av
  2. let t = tuple(1, 2, "hello", 3.14);
  3. println("type of t: " + type(t));
  4. for x in t {
  5. println(x);
  6. }
  7. println("count of t: "+ count(t));
  8. println("t[0] = " + t[0]);
  9. t[0] = 100;
  10. println("t[0] = " + t[0]);

这个例子演示了 tuple 的基本操作: for 用来遍历数组, count 可以获取数组长度t[x] 可以访问索引位置 x 的元素,同样也可以赋值特定位置的元素:

  1. type of t: Object[]
  2. 1
  3. 2
  4. hello
  5. 3.14
  6. count of t: 4
  7. t[0] = 1
  8. t[0] = 100

tuple 可以放入任意类型的元素,如果要创建特定类型的,就需要用到其他函数。

创建类型数组并填充

可以通过 seq.array(type, ..args) 可以创建 type 类型的数组:

  1. ## examples/array.av
  2. let a = seq.array(int, 1, 2, 3, 4);
  3. println("type(a) is : " + type(a));
  4. println("count(a) is: " + count(a));

比如上面创建了一个 int[] 数组,他的长度是 4,元素分别为 1, 2, 3, 4

如果传入错误的类型,创建将报错:

  1. let a = seq.array(int, 1, 2, "hello", 4);

报错 Unexpected param type, expected: int, given: java.lang.String

但是如果可以转化为目标类型,比如 double 可以转成 int ,那么还是可以创建的:

  1. let a = seq.array(int, 1, 2, 3.3, 4);
  2. map(a, println)

3.3 将被转为 3:

  1. 1
  2. 2
  3. 3
  4. 4

seq.array 的 type 可以是基本类型,如 shortbytecharboolfloatdoubleintlong 以及 void

也可以是对象,但是需要给完整的类名,比如创建字符串数组:

  1. let s = seq.array(java.lang.String, "hello", "world", "aviator");
  2. println(string.join(s, ","));

string.join 函数将第一个参数的字符串集合用第二个参数的字符串起来,这里将输出 hello,world,aviator

创建空数组

如果要创建一个“空”数组,只确定类型和长度,可以用 seq.array_of(type, len) ,这样就创建了一个 type[len] 的数组,每个元素都将是该类型的默认值,比如整数就是 0,对象就是 null:

  1. let a = seq.array_of(int, 3);
  2. println("type(a) is : " + type(a));
  3. println("count(a) is: " + count(a));
  4. println("before assignment:");
  5. for x in a {
  6. println(x);
  7. }
  8. for i in range(0, 3) {
  9. a[i] = i;
  10. }
  11. println("after assignment:");
  12. for x in a {
  13. println(x);
  14. }

输出:

  1. type(a) is : int[]
  2. count(a) is: 3
  3. before assignment:
  4. 0
  5. 0
  6. 0
  7. after assignment:
  8. 0
  9. 1
  10. 2

创建多维数组

seq.array_of(Class, &dimensions) 也可以用于创建多维数组,举例来说:

  1. ## create multidimensional array
  2. let a = seq.array_of(long, 3, 2);
  3. assert(3 == count(a));
  4. assert(2 == count(a[0]));
  5. let x = 0;
  6. for i in range(0, 3) {
  7. for j in range(0, 2) {
  8. a[i][j] = x;
  9. x = x + 1;
  10. }
  11. }
  12. for i in range(0, 3) {
  13. for j in range(0, 2) {
  14. p("a[#{i}][#{j}] = #{a[i][j]}");
  15. }
  16. }

我们创建了一个 2 x 3 的二维数组,并遍历初始化,最终打印数组:

  1. a[0][0] = 0
  2. a[0][1] = 1
  3. a[1][0] = 2
  4. a[1][1] = 3
  5. a[2][0] = 4
  6. a[2][1] = 5

遍历数组

上面其实已经演示了用 map 和 for 遍历数组的例子了,两者皆可,不过 map 将收集返回结果放入 collector 集合并返回,通常来说,如果你不需要结果,还是应当用 for 循环:

  1. let a = seq.array(int, 1, 2, 3.3, 4);
  2. for x in a {
  3. println(x);
  4. }

集合 List, Map 和 Set

在 AviatorScript 中也可以创建 java 的各种常见集合类型,比如 java.util.List、java.util.Map 和 java.util.Set 等。我们将一一介绍。

创建 List

创建一个链表可以通过 seq.list 函数:

  1. let list = seq.list(1, 2, 3);

上面将创建三个整数组成的 ArrayList 对象, seq.list 接受不定参数,如果不传入任何参数,创建的是一个空链表:

  1. let empty_list = seq.list();

链表和数组类似,也可以通过 a[i] = x 的方式来赋值,前提是 i 落在长度内

  1. ## examples/list.av
  2. let list = seq.list(1, 2, 3);
  3. list[0] = 4;
  4. list[1] = 5;
  5. list[2] = 6;
  6. println(list);

如果你尝试给长度范围之外的位置赋值,都将报错:

  1. list[3] = 7;

报错:

  1. Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 3, Size: 3

因此你无法通过位置赋值的方式为一个空链表添加元素,我们将在后面操作集合里介绍添加元素的方式。

repeat 和 repeatedly

repeat(n, x) 函数用来创建一个全部是 x 的 List,并且个数为 n:

  1. ## examples/repeat.av
  2. let list = repeat(10, "a");
  3. p("type of list: " + type(list));
  4. p("count of list: " + count(list));
  5. p("list[0]=" + list[0]);
  6. p("list is: " + list);

上面的例子将创建 10 个字符串 a 组成的链表:

  1. type of list: java.util.ArrayList
  2. count of list: 10
  3. list[0]=a
  4. list is: [a, a, a, a, a, a, a, a, a, a]

如果你有一个函数,可以产生元素,你想重复调用 n 次来产生一个集合,可以用 repeatedly(n, fn)

  1. let c = 0 ;
  2. let counter = lambda() ->
  3. c = c + 1;
  4. return c;
  5. end;
  6. let list = repeatedly(10, counter);
  7. p("type of list: " + type(list));
  8. p("count of list: " + count(list));
  9. p("list[0]=" + list[0]);
  10. p("list is: " + list);

我们创建了一个闭包函数 counter ,每次调用它会返回一个数字,并且数字从 1 开始递增,然后传入 repeatedly 调用 10 次,这就产生了一个 1~10 的数字集合:

  1. type of list: java.util.ArrayList
  2. count of list: 10
  3. list[0]=1
  4. list is: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

创建 Map

创建一个 HashMap 也很容易,使用 seq.map(k1, v1, k2, v2 ...) 的方式:

  1. ## examples/hash_map.av
  2. let m = seq.map("a", 1, "b", 2, "c", 3, 4, 5);
  3. println(m);

key 并不要求类型一致,比如这里 key=4 ,对应的值是 5:

  1. {a=1, b=2, c=3, 4=5}

seq.map 接受偶数个参数或者 0 个参数,不传入任何参数就是一个空的 map,可以通过 seq.put 来增加元素。

同样,对于 map ,你可以用 m.{key} 的方式来访问:

  1. println("m.a = " + m.a);
  2. println("m.b = " + m.b);
  3. println("m.c = " + m.c);

但是如果你的 key 不是合法的变量,就不能用这样的方式访问了,需要用到 seq.get 函数:

  1. println("m.4 = " + seq.get(m, 4));

可以赋值:

  1. m.a = 100;
  2. println("m.a = " + m.a);

但是,如果 key 不是合法变量,就需要用到 seq.put 函数:

  1. seq.put(m, 4, 99);
  2. println("m.4 = " + seq.get(m, 4));

为什么不是 _seq.set_ 呢? 因为 _seq.set_ 是用于创建集合 set 的。

从 5.2 开始,可以使用类似数组的语法 **map[key]** 来获取和设置值:

  1. m["a"] = 'aviator';
  2. println("m['a'] = " + m['a']);

<br />

key 和 value 集合

如果要获取 key 的集合,可以用 seq.keys(m) 函数, value 集合是用 seq.vals 函数:

  1. p("key set: " + seq.keys(m));
  2. p("value set: " + seq.vals(m));

输出:

  1. key set: [a, b, c, 4]
  2. value set: [aviator, 2, 3, 99]


创建 Set

创建不重复的元素组成的集合 Set,可以用 seq.set

  1. ## examples/hash_set.av
  2. let s = seq.set(1, 2, 2, "hello", 3.3, "hello");
  3. println(s);
  4. println("type(s) is: " + type(s));

输出:

  1. [1, 2, hello, 3.3]
  2. type(s) is: java.util.HashSet

我们传入的参数有重复的 2 和字符串 hello,但是最终结果是一个去重的集合 java.util.HashSet
Set 最常见的操作是判断某个元素是否存在,可以用 include 函数:

  1. println(include(s, 1));
  2. println(include(s, "hello"));
  3. println(include(s, 100));

输出:

  1. true
  2. true
  3. false

操作集合

这里我们介绍操作这些集合类的通用操作,首先是添加元素。

添加元素 seq.add

往集合里添加元素可以用上面介绍过的 seq.add(coll, element) ,它支持 List/Set ,同时他有一个三参数版本 seq.add(coll, key, value) 可以用于添加键值对到 map:

  1. ## examples/collections.av
  2. let list = seq.list();
  3. let set = seq.set();
  4. let map = seq.map();
  5. ## add elements
  6. for i in range(0, 3) {
  7. seq.add(list, i);
  8. seq.add(set, i);
  9. seq.add(map, i, i);
  10. }
  11. println("list: " + list);
  12. println("set: " + set);
  13. println("map: " + map);

输出:

  1. list: [0, 1, 2]
  2. set: [0, 1, 2]
  3. map: {0=0, 1=1, 2=2}

如果你的元素类型是 Map.Entry ,也可以直接调用 seq.add(m, e) 来添加:

  1. 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。
  1. ## retrieve elements by seq.get
  2. for i in range(0, 3) {
  3. assert(i == seq.get(list, i));
  4. assert(i == seq.get(set, i));
  5. assert(i == seq.get(map, i));
  6. }
  7. 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 方法。

  1. for i in range(0, 3) {
  2. assert(include(list, i));
  3. assert(include(set, i));
  4. }
  5. assert(!include(list, 5));
  6. assert(!include(set, 5));

对于 map 来说,如果是判断 key 是否存在,需要用 seq.contains_key(coll, key)

  1. for i in range(0, 3) {
  2. assert(seq.contains_key(map, i));
  3. }
  4. assert(!seq.contains_key(map, 5));

如果是判断 Map.Entry 是否存在,仍然继续使用 include

  1. for i in range(0, 3) {
  2. assert(include(map, seq.entry(i, i)));
  3. }

遍历集合

遍历集合和数组的方式一样,同样通过 for..in 语句:

  1. ## Iterate the collection by for..in loop
  2. println("list elements:");
  3. for x in list {
  4. println(x);
  5. }
  6. println("set elements:");
  7. for x in set {
  8. println(x);
  9. }
  10. println("map elements:");
  11. for x in map {
  12. println(x.key + "=" + x.value);
  13. }

对于 map 来说迭代循环中的元素就是 Map.Entry 对象,可以通过 key 和 value 属性来访问键和值。
输出:

  1. list elements:
  2. 0
  3. 1
  4. 2
  5. set elements:
  6. 0
  7. 1
  8. 2
  9. map elements:
  10. 0=0
  11. 1=1
  12. 2=2

删除元素 seq.remove

删除元素也是常见的需求,可以用 seq.remove(coll, element) ,对于 List/Set 和 Map 都是如此,如果是 Map,传入的应该是 key:

  1. ## remove elements
  2. assert(list == seq.remove(list, 2));
  3. assert(list == seq.remove(list, 4));
  4. assert(set == seq.remove(set, 1));
  5. assert(map == seq.remove(map, 0));
  6. println("list: " + list);
  7. println("set: " + set);
  8. println("map: " + map);

打印:

  1. list: [0, 1]
  2. set: [0, 2]
  3. map: {1=1, 2=2}

可见删除生效了,删除不存在的元素不产生影响。 seq.remove 返回的是删除后的集合对象。