Wiki

root/cobra/trunk/HowTo/180-UseLists.cobra

Revision 2335, 8.1 KB (checked in by Chuck.Esterbrook, 2 years ago)

Improvements to the How-To's.

  • Property svn:eol-style set to native
Line 
1class HowToUseLists
2
3    def main
4        .basics
5        .looping
6        .literals
7        .stringConversion
8        .operators
9        .methods
10
11    def basics
12        # a list literal starts with [ and ends with ]
13        # elements are separated by commas
14        ints = [1, 2, 3]
15       
16        # a list has a number of elements - the .count
17        assert ints.count == 3
18       
19        # lists can be indexed with brackets, starting with 0
20        assert ints[0] == 1 and ints[1] == 2 and ints[2] == 3
21       
22        # .last gives the last element
23        assert ints.last == 3
24       
25        # out bounds is an exception
26        expect ArgumentOutOfRangeException, print ints[5]
27       
28        # .get allows a default value to be returned if the index is out of bounds
29        assert ints.get(3, -1) == -1
30       
31        # .get allows negative indexes where -1 is the last element
32        # -2 is the second to last
33        assert ints.get(-2) == 2
34       
35        # a negative index can still be out of bounds
36        expect Exception, ints.get(-4)
37        assert ints.get(-4, -1) == -1   # ...but you can provide a default value
38       
39        # lists can be compared
40        assert ints == [1, 2, 3]
41
42    def looping
43        names = ['foo', 'bar', 'baz']
44
45        # looping is easy
46        for name in names
47            assert name.length == 3
48       
49        # loop through a sorted version
50        last = ''
51        for name in names.sorted
52            assert name > last
53            last = name
54        # the original list is unchanged
55        assert names == ['foo', 'bar', 'baz']
56       
57        # loop through a reversed version
58        for name in names.reversed
59            assert name.length == 3
60        # again the original list is unchanged
61        assert names == ['foo', 'bar', 'baz']
62       
63        # get an index with each element
64        order = []
65        for i, name in names.numbered
66            branch i
67                on 0, assert name == 'foo'
68                on 1, assert name == 'bar'
69                on 2, assert name == 'baz'
70            order.add(i)
71        assert order == [0, 1, 2]
72       
73        # get an index with each element, but in reverse
74        order = []
75        for i, name in names.numberedDown
76            branch i
77                on 0, assert name == 'foo'
78                on 1, assert name == 'bar'
79                on 2, assert name == 'baz'
80            order.add(i)
81        assert order == [2, 1, 0]
82       
83        # loop through the indexes only because the list will be modified
84        for i in names.count
85            names[i] = names[i].toUpper
86        assert names == ['FOO', 'BAR', 'BAZ']
87   
88    def literals
89        # you've seen these above
90        ints = [1, 2, 3]
91        for i in ints, assert i > 0
92       
93        names = ['foo', 'bar', 'baz']
94        for name in names, assert name.length == 3
95       
96        # list literals can span lines
97        names = [
98            'foo',
99            'bar',
100            'baz',  # trailing comma is optional
101        ]
102       
103        # lists can be nested
104        pairs = [
105            [0, 0],
106            [-2, -3],
107            [5, 2],
108        ]
109        for pair in pairs
110            assert pair.count == 2
111        for x, y in pairs
112            assert x > -10 and y > -10
113
114        # lists can have other types of collections in them
115        sites = [
116            {'name': 'Cobra', 'url': 'http://cobra-language.com/'},
117            {'name': 'Wikipedia', 'url': 'http://en.wikipedia.org/'},
118        ]
119        for dict in sites
120            assert dict.count == 2
121            assert dict['url'].startsWith('http://')
122       
123        # lists can have object instantiations in them
124        points = [Point(0, 0), Point(1, 1), Point(0, 1), Point(1, 0)]
125        assert points[0].toString == 'Point(0, 0)'
126       
127        # lists can be heterogenous
128        stuff = ['foo', 5, nil]
129        assert stuff.reversed == [nil, 5, 'foo']
130
131        # the inferred type for a list is as narrow as possible
132        ints = [1, 2, 3]               # List<of int>
133        names = ['foo', 'bar', 'baz']  # List<of String>
134        sites = [{'a': 'b'}]           # List<of Dictionary<of String, String>>
135        points = [Point(0, 0)]         # List<of Point>
136        stuff = ['foo', 5, nil]        # List<of dynamic?>
137        stuff = []    # an empty list is List<of dynamic?>
138   
139    def stringConversion
140        ints = [1, 2, 3]
141       
142        # list to string is ugly in .NET
143        assert ints.toString == r'System.Collections.Generic.List`1[System.Int32]'
144        # cobra also provides
145        assert ints.toPrintString == r'[1, 2, 3]'
146
147        # string substitution
148        assert 'the ints are [ints]' == r'the ints are [1, 2, 3]'
149       
150        # print
151        print ints  # prints: [1, 2, 3]
152       
153        # print each element
154        for i in ints
155            print i
156        for index, i in ints.numbered
157            print '[index]. [i]'
158       
159        # trace
160        trace ints  # trace: ints=List<of int>[1, 2, 3]; at x-how-to-list.cobra:163;
161                    #        in HowToUseLists.stringConversion
162
163        # joining list elements into a string
164        assert ints.join(' ') == '1 2 3'
165        assert ints.join('---') == '1---2---3'
166        assert ints.join(', ', ' and ') == '1, 2 and 3'
167
168    def operators
169        # you can concatenate two lists with +
170        # the original lists are not changed
171        a = [1, 2]
172        b = [3, 4]
173        assert a + b == [1, 2, 3, 4]
174        assert a == [1, 2] and b == [3, 4]
175       
176        # the expression `x in items` evaluates to true or false
177        # you can also write `x not in items`
178        ints = [1, 2, 3]
179        assert 1 in ints
180        assert 2 in ints and 3 in ints
181        assert 0 not in ints
182        assert 4 not in ints
183   
184        # the expression `all items` evaluates to true if every item is true
185        # the expression `any items` evaluates to true if any item is true
186        ints = [1, 2, 3]
187        assert all ints
188        assert any ints
189        ints = [0, 1, 2, 3]
190        assert not all ints
191        assert any ints
192        ints = [0, 0]
193        assert not all ints
194        assert not any ints
195       
196        # the equality operators can be used on lists
197        assert [1, 2] == [2, 1].reversed
198        assert [1, 2] <> [2, 1]
199
200    def methods
201        # add an element to a list
202        names = ['foo', 'bar', 'baz']
203        names.add('qux')
204        assert names == ['foo', 'bar', 'baz', 'qux']
205       
206        # add multiple elements to a list
207        names.addRange(['x', 'y'])
208        assert names == ['foo', 'bar', 'baz', 'qux', 'x', 'y']
209       
210        # insert an element
211        names.insert(1, 'fooey')
212        assert names == ['foo', 'fooey', 'bar', 'baz', 'qux', 'x', 'y']
213        names.insert(7, 'z')  # 7 is just past the end of the list
214        assert names == ['foo', 'fooey', 'bar', 'baz', 'qux', 'x', 'y', 'z']
215        expect ArgumentOutOfRangeException, names.insert(20, 'exception')
216       
217        # clear a list
218        names.clear
219        assert names.count == 0
220       
221        # find an item's index
222        names = ['foo', 'bar', 'baz', 'foo']
223        assert names.indexOf('foo') == 0
224        assert names.indexOf('baz') == 2
225        assert names.indexOf('not there') == -1
226        assert names.lastIndexOf('foo') == 3
227       
228        # find an item's index in a subrange of the list
229        assert names.indexOf('foo', 1) == 3      # start at 1
230        assert names.indexOf('foo', 1, 2) == -1  # start at 1, search 2 items
231       
232        # TODO: left off on .insertRange
233       
234        # additional methods. search web for "msdn generic list"
235        # .asReadOnly .binarySearch .convertAll .copyTo .exists .find .findAll .findIndex .findLast .findListIndex .forEach
236       
237       
238
239class Point
240
241    cue init(x as int, y as int)
242        base.init
243        _x, _y = x, y
244   
245    def equals(other) as bool is override
246        if other is nil, return false
247        if other inherits Point, return .x == other.x and .y == other.y
248        return false
249
250    def getHashCode as int is override
251        return .x ^ .y
252
253    get x from var as int
254   
255    get y from var as int
256   
257    def toString as String is override
258        return '[.typeOf.name]([.x], [.y])'
259
260
261# although it's not common to subclass the list type,
262# you are certainly free to do so
263
264# a generic subclass
265
266class MyList<of T> inherits List<of T>
267
268    get middle as T
269        require .count > 0
270        return this[.count // 2]
271
272
273# a subclass with specific type
274
275class PointList inherits List<of Point>
276
277    test
278        pl = PointList()
279        pl.add(Point(1, 0))
280        pl.add(Point(-2, 3))
281        assert pl.count == 2
282        assert pl.leftMost == Point(-2, 3)
283   
284    def leftMost as Point
285        require .count > 0
286        leftMost = this[0]
287        for i in 1 : .count
288            if this[i].x < leftMost.x
289                leftMost = this[i]
290        return leftMost
291
292
293# a generic subclass with a type constraint is even better,
294# because then you can specify a type parameter when using it
295
296class PointList<of TPoint> inherits List<of TPoint>
297    where TPoint must be Point  # the type constraint
298
299    test
300        pl = PointList<of Point>()
301        pl.add(Point(1, 0))
302        pl.add(Point(-2, 3))
303        assert pl.count == 2
304        assert pl.leftMost == Point(-2, 3)
305   
306    def leftMost as TPoint  # notice the return type is TPoint
307        require .count > 0
308        leftMost = this[0]
309        for i in 1 : .count
310            if this[i].x < leftMost.x
311                leftMost = this[i]
312        return leftMost
313
314        # TODO:
315
316        # slicing
317       
318        # customers.sort(ref .orderByTotalSpent)
319        # sort with do
320       
321        # declaring types
322        # List vs. IList
323        # List methods
324        # all extension methods
325        # check msdn docs on IList and List
326        # any enumerable .toList
327        # for expression returns a list
Note: See TracBrowser for help on using the browser.