官术网_书友最值得收藏!

Data structures

The only way to build data structures in Opa is to use records, which we will talk about later on. All other data structures, such as tuples and lists, are based on records. Opa provides different modules to help the user to manipulate lists and maps. Let's first have a look at records.

Records

Simply speaking, a record is a collection of data. Here is how to build a record:

x = {} // the empty record
x = {a:2,b:3} //a record with field "a" and "b"

The empty record,{}, has a synonym, void, which means the same thing. There are a number of syntactic shortcuts available to write records concisely. First, if you give a field name without the field value, it means the value of this field is void:

x = {a}      // means {a:void}
x = {a, b:2} // means {a:void b:2}

The second shorthand we always use is the sign ~. It means if the field value is left empty, assign it with a variable having the same name as the field name:

x = {~a, b:2}    // means {a:a, b:2}
x = ~{a, b}      // means {a:a, b:b}
x = ~{a, b, c:4} // means {a:a, b:b, c:4}
x = ~{a:{b}, c}  // means {a:{b:void}, c:c}, NOT {a:{b:b}, c:c}
//Consider this more meaningful example
name = "Li"; sex  = "Male"; age  = 28; 
person = ~{name, sex, age} //means {name:"Li", sex:"Male", age: 28}

We can also build a record deriving from an existing record using the keyword with:

x = {a:1,b:2,c:3}
y = {x with a:"1",b:5} // y = {a:"1", b:5, c:3}

Note that you can redefine as many fields as you want. In the example we saw just now, the field a in y is a string, but the field a in x is an integer. Here are some more examples about deriving:

X = {a:1, b:{c:"2", d:3.0}}
// you can update fields deep in the record
y = {x with b.c:"200"}  // y = {a:1, b:{c:"200", d:3.0}}
// you can use the same syntactic shortcuts as used before
y = {x with a}          // means {x with a:void}
y = {x with ~a}         // means {x with a:a}
y = ~{x with a, b:{e}}  // means {x with a:a, b:{e}}
Tuples

An N-tuple is a sequence of n elements, where N is a positive integer. In Opa, an N-tuple is just a record with fields f1 to fN:

x = (1,)          // a tuple of size 1, the same as {f1:1}
x = (1,"2",{a:3}) // a size 3 tuple, the same as {f1:1, f2:"2", f3:{a:3}} 
y = {x with f1:2} // we can manipulate a tuple the same way as a 
                    //record
// y = {f1:2, f2:"2", f3:{a:3}}

Note the trailing comma in the first case; it differentiates a 1-tuple from a parenthesized expression. The trailing comma is allowed for any other tuple, although, it makes no difference whether you write it or not in these cases.

Lists

In Opa, a list (linked list) is an immutable data structure, meant to contain finite or infinite sets of elements of the same type. Actually, list is just a record with special structures, which is defined as:

type list('a) = {nil} or {'a hd, list('a) tl}

Here is how to build lists:

x = []      // the empty list, equals to {nil}
x = [2,3,4] // a three element list, the same as a record: 
             // {hd:2, tl:{hd:3, tl:{hd:4, tl:{nil}}}}
y = [0,1|x] // this will put 0,1 on top of x: [0,1,2,3,4]

Lists in Opa are much like arrays in C language and Java. But there are differences. First, lists are immutable in Opa, which means elements of a list cannot be changed by assignment. Second, the way we manipulate lists are different. We use the module List (http://doc.opalang.org/module/stdlib.core/List) to manage lists in Opa. The following are the most commonly used operations on lists (which will be explained in the subsequent sections):

l = [1,2,3]
len = List.length(l)       // return the length of a list
isEmpty = List.is_empty(l) // test if a list is empty
head = List.head(l)        // get the first element, will fail if 
                             // the list is empty
element = List.get(0,l)    // get nth element, return option('a)
l1 = List.add(4,l)         // adding an element at the head of a 
                             //list
l2 = 4 +> l                // a shortcut for List.add
l3 = List.remove(3,l)      // removing an element
l4 = List.drop(2,l)        // drop the first n elements
Iterating through a list

In C language or Java, we use a for or a while loop to iterate through lists or arrays. They look something like this:

int[] numbers = [1,2,3,4,5]
for(int i=0; i<numbers.length; i++){ //do something }

But in Opa, it is totally different. To loop through a list, we use List.fold or List.foldi. List.fold is a powerful function that you can use to do almost anything you want on a list. Here is a simple example of getting the length of a list:

len = List.fold(function(_,i){ i+1 }, ["a","b","c"], 0)

List.fold takes three parameters. The first is a function, the second is the list, and the third is an initial value. It loops through the list and applies the function on each element. So, if we name the function f, it is executed something like this:

len = f("c", f("b", f("a",0)))

First, f("a",0) will be executed and will return 1, here 0 is the initial value and a is the first element. Then f("b",1) will return 2 and at last f("c",2) will return 3. Here is a little more complicated example:

//find the max natural number in the list
max = List.fold(function(x,a){ 
  if(x > a) x else a
},[1,4,3,2,7,8,5],0)
Finding elements

We have many ways to find an element in a list. List.index searches the first occurrence of an element and returns its index. List.index_p searches the first occurrence of any element matching a given function and returns its index. List.find is the same as List.index_p, but returns the element itself but not its index. For example:

l = ["a","b","c"]
r1 = List.index("b",l)                      // r1 = {some:1}
r2 = List.index("x",l)                      // r2 = {none}
r3 = List.index_p(function(x){ x == "b"},l) // r3 = {some:1}
r4 = List.find(function(x){ x == "b"},l)    // r4 = {some:"b"}
Transforming lists

If you want to project elements to a new list, for example doubling the number in a list or selecting the odd numbers, you can do this with List.map and List.filter. Here are some examples:

l1 = [1,2,3,4,5]
l2 = List.map(function(x){ 2*x }, l1); //l2 = [2,4,6,8,10]
l3 = List.filter(function(x){mod(x,2) == 0},l1); // l3 = [2,4]
Sorting a list

Call the function List.sort to sort a list in the usual order. The usual order means the default order, that is, numbers from small to big and strings in alphabetical order. Consider the following code:

l1 = List.sort(["by","as","of","At"]) //l1 = ["At","as","by","of"]
l2 = List.sort([1,3,4,6,2])           //l2 = [1,2,3,4,6]

List.sort_by uses the usual order, but it projects elements, for example, converting strings to lower-case before comparing them. List.sort_with allows us to use our own comparing function.

To make that clear, suppose there are three points, P1 (1, 3), P2 (3, 2), and P3 (2, 1), and we want to sort them in two different ways:

  • By their Y coordinates
  • By distance from the origin of the coordinates (0, 0)

Let's see how to do that in Opa:

p = [{x:1,y:3},{x:3,y:2},{x:2,y:1}]
l1 = List.sort_with(function(p1,p2){  // sort by Y corordination
  if(p1.y >= p2.y) {gt} else {lt}
},p)
l2 = List.sort_by(function(p){        //sort by distance
  p.x*p.x + p.y*p.y    
},p)

Maps

Maps are an important data structure just like lists. The most common cases of maps in Opa are stringmap and intmap. stringmap is a map from string to value of some type, while intmap is a map from numbers to value of some type.

The way we manipulate maps is almost the same as lists, it is unwise to repeat it again. Here are some of the most used operations:

m1 = Map.empty                 // create an empty map
m2 = StringMap.empty           // create an empty stringmap
m3 = IntMap.empty              // create an empty intmap
m4 = Map.add("key1","val1",m1) // adding a key-val pair
v1 = Map.get("key1",m4)        // getting a value
m5 = Map.remove("key1",m4)     // removing a key
主站蜘蛛池模板: 定安县| 乐昌市| 安乡县| 阿尔山市| 三穗县| 瓮安县| 察雅县| 双牌县| 资阳市| 镇康县| 苏尼特右旗| 和平县| 凯里市| 九龙城区| 视频| 托克逊县| 双峰县| 琼结县| 雷州市| 丹棱县| 新兴县| 项城市| 通州区| 安顺市| 瑞金市| 商都县| 定西市| 姜堰市| 伊宁市| 景德镇市| 荥阳市| 丽江市| 灌南县| 朔州市| 龙州县| 肇源县| 贵港市| 右玉县| 诸暨市| 满城县| 喀喇沁旗|