Java使用Aviator表达式 学习记录(十八)

7,668 阅读6分钟

这是我参与8月更文挑战的第20天,活动详情查看:8月更文挑战

遍历数组

 上面其实已经演示了用 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.av

let 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.av

let 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.ArrayList
count of list: 10
list[0]=a
list 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.ArrayList
count of list: 10
list[0]=1
list is: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

创建 Map

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

## examples/hash_map.av
let 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']);

**

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.av

let 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));	

输出:

true
true
false

操作集合

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

添加元素 seq.add

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

## examples/collections.av

let list = seq.list();
let set = seq.set();
let map = seq.map();

## add elements
for 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.get
for 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 loop
println("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:
0
1
2
set elements:
0
1
2
map elements:
0=0
1=1
2=2

删除元素 seq.remove

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

## remove elements
assert(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 返回的是删除后的集合对象。