class HowToUseLists def main .basics .looping .literals .stringConversion .operators .methods def basics # a list literal starts with [ and ends with ] # elements are separated by commas ints = [1, 2, 3] # a list has a number of elements - the .count assert ints.count == 3 # lists can be indexed with brackets, starting with 0 assert ints[0] == 1 and ints[1] == 2 and ints[2] == 3 # .last gives the last element assert ints.last == 3 # out bounds is an exception expect ArgumentOutOfRangeException, print ints[5] # .get allows a default value to be returned if the index is out of bounds assert ints.get(3, -1) == -1 # .get allows negative indexes where -1 is the last element # -2 is the second to last assert ints.get(-2) == 2 # a negative index can still be out of bounds expect Exception, ints.get(-4) assert ints.get(-4, -1) == -1 # ...but you can provide a default value # lists can be compared assert ints == [1, 2, 3] def looping names = ['foo', 'bar', 'baz'] # looping is easy for name in names assert name.length == 3 # loop through a sorted version last = '' for name in names.sorted assert name > last last = name # the original list is unchanged assert names == ['foo', 'bar', 'baz'] # loop through a reversed version for name in names.reversed assert name.length == 3 # again the original list is unchanged assert names == ['foo', 'bar', 'baz'] # get an index with each element order = [] for i, name in names.numbered branch i on 0, assert name == 'foo' on 1, assert name == 'bar' on 2, assert name == 'baz' order.add(i) assert order == [0, 1, 2] # get an index with each element, but in reverse order = [] for i, name in names.numberedDown branch i on 0, assert name == 'foo' on 1, assert name == 'bar' on 2, assert name == 'baz' order.add(i) assert order == [2, 1, 0] # loop through the indexes only because the list will be modified for i in names.count names[i] = names[i].toUpper assert names == ['FOO', 'BAR', 'BAZ'] def literals # you've seen these above ints = [1, 2, 3] for i in ints, assert i > 0 names = ['foo', 'bar', 'baz'] for name in names, assert name.length == 3 # list literals can span lines names = [ 'foo', 'bar', 'baz', # trailing comma is optional ] # lists can be nested pairs = [ [0, 0], [-2, -3], [5, 2], ] for pair in pairs assert pair.count == 2 for x, y in pairs assert x > -10 and y > -10 # lists can have other types of collections in them sites = [ {'name': 'Cobra', 'url': 'http://cobra-language.com/'}, {'name': 'Wikipedia', 'url': 'http://en.wikipedia.org/'}, ] for dict in sites assert dict.count == 2 assert dict['url'].startsWith('http://') # lists can have object instantiations in them points = [Point(0, 0), Point(1, 1), Point(0, 1), Point(1, 0)] assert points[0].toString == 'Point(0, 0)' # lists can be heterogenous stuff = ['foo', 5, nil] assert stuff.reversed == [nil, 5, 'foo'] # the inferred type for a list is as narrow as possible ints = [1, 2, 3] # List<of int> names = ['foo', 'bar', 'baz'] # List<of String> sites = [{'a': 'b'}] # List<of Dictionary<of String, String>> points = [Point(0, 0)] # List<of Point> stuff = ['foo', 5, nil] # List<of dynamic?> stuff = [] # an empty list is List<of dynamic?> def stringConversion ints = [1, 2, 3] # list to string is ugly in .NET assert ints.toString == r'System.Collections.Generic.List`1[System.Int32]' # cobra also provides assert ints.toPrintString == r'[1, 2, 3]' # string substitution assert 'the ints are [ints]' == r'the ints are [1, 2, 3]' # print print ints # prints: [1, 2, 3] # print each element for i in ints print i for index, i in ints.numbered print '[index]. [i]' # trace trace ints # trace: ints=List<of int>[1, 2, 3]; at x-how-to-list.cobra:163; # in HowToUseLists.stringConversion # joining list elements into a string assert ints.join(' ') == '1 2 3' assert ints.join('---') == '1---2---3' assert ints.join(', ', ' and ') == '1, 2 and 3' def operators # you can concatenate two lists with + # the original lists are not changed a = [1, 2] b = [3, 4] assert a + b == [1, 2, 3, 4] assert a == [1, 2] and b == [3, 4] # the expression `x in items` evaluates to true or false # you can also write `x not in items` ints = [1, 2, 3] assert 1 in ints assert 2 in ints and 3 in ints assert 0 not in ints assert 4 not in ints # the expression `all items` evaluates to true if every item is true # the expression `any items` evaluates to true if any item is true ints = [1, 2, 3] assert all ints assert any ints ints = [0, 1, 2, 3] assert not all ints assert any ints ints = [0, 0] assert not all ints assert not any ints # the equality operators can be used on lists assert [1, 2] == [2, 1].reversed assert [1, 2] <> [2, 1] def methods # add an element to a list names = ['foo', 'bar', 'baz'] names.add('qux') assert names == ['foo', 'bar', 'baz', 'qux'] # add multiple elements to a list names.addRange(['x', 'y']) assert names == ['foo', 'bar', 'baz', 'qux', 'x', 'y'] # insert an element names.insert(1, 'fooey') assert names == ['foo', 'fooey', 'bar', 'baz', 'qux', 'x', 'y'] names.insert(7, 'z') # 7 is just past the end of the list assert names == ['foo', 'fooey', 'bar', 'baz', 'qux', 'x', 'y', 'z'] expect ArgumentOutOfRangeException, names.insert(20, 'exception') # clear a list names.clear assert names.count == 0 # find an item's index names = ['foo', 'bar', 'baz', 'foo'] assert names.indexOf('foo') == 0 assert names.indexOf('baz') == 2 assert names.indexOf('not there') == -1 assert names.lastIndexOf('foo') == 3 # find an item's index in a subrange of the list assert names.indexOf('foo', 1) == 3 # start at 1 assert names.indexOf('foo', 1, 2) == -1 # start at 1, search 2 items # TODO: left off on .insertRange # additional methods. search web for "msdn generic list" # .asReadOnly .binarySearch .convertAll .copyTo .exists .find .findAll .findIndex .findLast .findListIndex .forEach class Point cue init(x as int, y as int) base.init _x, _y = x, y def equals(other) as bool is override if other is nil, return false if other inherits Point, return .x == other.x and .y == other.y return false def getHashCode as int is override return .x ^ .y get x from var as int get y from var as int def toString as String is override return '[.typeOf.name]([.x], [.y])' # although it's not common to subclass the list type, # you are certainly free to do so # a generic subclass class MyList<of T> inherits List<of T> get middle as T require .count > 0 return this[.count // 2] # a subclass with specific type class PointList inherits List<of Point> test pl = PointList() pl.add(Point(1, 0)) pl.add(Point(-2, 3)) assert pl.count == 2 assert pl.leftMost == Point(-2, 3) def leftMost as Point require .count > 0 leftMost = this[0] for i in 1 : .count if this[i].x < leftMost.x leftMost = this[i] return leftMost # a generic subclass with a type constraint is even better, # because then you can specify a type parameter when using it class PointList<of TPoint> inherits List<of TPoint> where TPoint must be Point # the type constraint test pl = PointList<of Point>() pl.add(Point(1, 0)) pl.add(Point(-2, 3)) assert pl.count == 2 assert pl.leftMost == Point(-2, 3) def leftMost as TPoint # notice the return type is TPoint require .count > 0 leftMost = this[0] for i in 1 : .count if this[i].x < leftMost.x leftMost = this[i] return leftMost # TODO: # slicing # customers.sort(ref .orderByTotalSpent) # sort with do # declaring types # List vs. IList # List methods # all extension methods # check msdn docs on IList and List # any enumerable .toList # for expression returns a list |
How To Use Lists