Contents
Vala Collections: libgee
You should install the Vala collection library, libgee, from your distribution.
More information about libgee is available from https://wiki.gnome.org/Projects/Libgee
List Example
using Gee;
void main () {
var list = new ArrayList<int> ();
list.add (1);
list.add (2);
list.add (5);
list.add (4);
list.insert (2, 3);
list.remove_at (3);
foreach (int i in list) {
stdout.printf ("%d\n", i);
}
list[2] = 10; // same as list.set (2, 10)
stdout.printf ("%d\n", list[2]); // same as list.get (2)
}
Compile and Run
$ valac --pkg gee-0.8 gee-list.vala $ ./gee-list
You can use any type fitting into the size of a pointer (e.g. int, bool, reference types) directly as generic type argument: <bool>, <int>, <string>, <MyObject>. Other types must be "boxed" by appending a question mark: <float?>, <double?>, <MyStruct?>. The compiler will tell you this if necessary.
Set Example
Sets are unordered and do not contain duplicate elements.
using Gee;
void main () {
var my_set = new HashSet<string> ();
my_set.add ("one");
my_set.add ("two");
my_set.add ("three");
my_set.add ("two"); // will not be added because it's a duplicate
foreach (string s in my_set) {
stdout.printf ("%s\n", s);
}
}
Compile and Run
$ valac --pkg gee-0.8 gee-set.vala $ ./gee-set
Map Example
Maps work like a dictionary. They store key - value pairs.
using Gee;
void main () {
var map = new HashMap<string, int> ();
// Setting values
map.set ("one", 1);
map.set ("two", 2);
map.set ("three", 3);
map["four"] = 4; // same as map.set ("four", 4)
map["five"] = 5;
// Getting values
int a = map.get ("four");
int b = map["four"]; // same as map.get ("four")
assert (a == b);
// Iteration
stdout.printf ("Iterating over entries\n");
foreach (var entry in map.entries) {
stdout.printf ("%s => %d\n", entry.key, entry.value);
}
stdout.printf ("Iterating over keys only\n");
foreach (string key in map.keys) {
stdout.printf ("%s\n", key);
}
stdout.printf ("Iterating over values only\n");
foreach (int value in map.values) {
stdout.printf ("%d\n", value);
}
stdout.printf ("Iterating via 'for' statement\n");
var it = map.map_iterator ();
for (var has_next = it.next (); has_next; has_next = it.next ()) {
stdout.printf ("%d\n", it.get_value ());
}
}
Compile and Run
$ valac --pkg gee-0.8 gee-map.vala $ ./gee-map
Syntactic Sugar
There's syntactic sugar for testing if a collection contains an element:
if ("three" in my_set) { // same as my_set.contains ("three")
stdout.printf ("heureka\n");
}
Customizing the equality function
bool same_book (Book a, Book b) {
return a.isbn == b.isbn;
}
// ...
var books = new Gee.ArrayList<Book> ((EqualFunc) same_book);
Implementing your own Iterable
You will have to implement two interfaces: Iterable with an iterator () method and an element_type property as well as an Iterator.
using Gee;
class RangeIterator : Object, Iterator<int> {
private Range range;
private int current;
public RangeIterator (Range range) {
this.range = range;
this.current = range.from - 1;
}
public bool next () {
if (!has_next ()) {
return false;
}
this.current++;
return true;
}
public bool has_next () {
return this.current < this.range.to;
}
public bool first () {
this.current = range.from;
return true;
}
/* Here the 'new' keyword is used because Object already
has a 'get' method. This will hide the original method.
Otherwise you'll get a warning. */
public new int get () {
return this.current;
}
public void remove () {
assert_not_reached ();
}
}
public class Range : Object, Iterable<int> {
public int from { get; private set; }
public int to { get; private set; }
public Range (int from, int to) {
assert (from < to);
this.from = from;
this.to = to;
}
public Type element_type {
get { return typeof (int); }
}
public Iterator<int> iterator () {
return new RangeIterator (this);
}
}
void main () {
foreach (int i in new Range (10, 20)) {
stdout.printf ("%d\n", i);
}
}
Compile and Run
$ valac --pkg gee-0.8 iterable.vala $ ./iterable
You could even add an each () method for Ruby or Groovy style iteration.
public class Range : Object, Iterable<int> {
// ... (as above)
public delegate void RangeEachFunc (int i);
public void each (RangeEachFunc each_func) {
foreach (int i in this) {
each_func (i);
}
}
}
void main () {
// Pass an anonymous function as parameter
new Range (10, 20).each ((i) => {
stdout.printf ("%d\n", i);
});
}