X-Git-Url: http://nitlanguage.org diff --git a/lib/standard/collection/abstract_collection.nit b/lib/standard/collection/abstract_collection.nit index 9d79de9..2f7e454 100644 --- a/lib/standard/collection/abstract_collection.nit +++ b/lib/standard/collection/abstract_collection.nit @@ -33,25 +33,29 @@ import kernel # Subclasses often provide a more efficient implementation. # # Because of the `iterator` method, Collections instances can use -# the `for` control structure: +# the `for` control structure. # -# var x: Collection[U] -# # ... -# for u in x do -# # u is a U -# # ... -# end +# ~~~nitish +# var x: Collection[U] +# # ... +# for u in x do +# # u is a U +# # ... +# end +# ~~~ # -# that is equivalent with +# that is equivalent with the following: # -# var x: Collection[U] -# # ... -# var i = x.iterator -# while i.is_ok do -# var u = i.item # u is a U -# # ... -# i.next -# end +# ~~~nitish +# var x: Collection[U] +# # ... +# var i = x.iterator +# while i.is_ok do +# var u = i.item # u is a U +# # ... +# i.next +# end +# ~~~ interface Collection[E] # Get a new iterator on the collection. fun iterator: Iterator[E] is abstract @@ -62,6 +66,14 @@ interface Collection[E] # assert [1..1[.is_empty == true fun is_empty: Bool do return length == 0 + # Alias for `not is_empty`. + # + # Some people prefer to have conditions grammatically easier to read. + # + # assert [1,2,3].not_empty == true + # assert [1..1[.not_empty == false + fun not_empty: Bool do return not self.is_empty + # Number of items in the collection. # # assert [10,20,30].length == 3 @@ -106,7 +118,7 @@ interface Collection[E] # How many occurrences of `item` are in the collection? # Comparisons are done with == # - # assert [10,20,10].count(10) == 2 + # assert [10,20,10].count(10) == 2 fun count(item: E): Int do var nb = 0 @@ -116,7 +128,7 @@ interface Collection[E] # Return the first item of the collection # - # assert [1,2,3].first == 1 + # assert [1,2,3].first == 1 fun first: E do assert length > 0 @@ -125,13 +137,13 @@ interface Collection[E] # Does the collection contain at least each element of `other`? # - # assert [1,3,4,2].has_all([1..2]) == true - # assert [1,3,4,2].has_all([1..5]) == false + # assert [1,3,4,2].has_all([1..2]) == true + # assert [1,3,4,2].has_all([1..5]) == false # # Repeated elements in the collections are not considered. # - # assert [1,1,1].has_all([1]) == true - # assert [1..5].has_all([1,1,1]) == true + # assert [1,1,1].has_all([1]) == true + # assert [1..5].has_all([1,1,1]) == true # # Note that the default implementation is general and correct for any lawful Collections. # It is memory-efficient but relies on `has` so may be CPU-inefficient for some kind of collections. @@ -140,10 +152,36 @@ interface Collection[E] for x in other do if not has(x) then return false return true end + + # Does the collection contain exactly all the elements of `other`? + # + # The same elements must be present in both `self` and `other`, + # but the order of the elements in the collections are not considered. + # + # assert [1..3].has_exactly([3,1,2]) == true # the same elements + # assert [1..3].has_exactly([3,1]) == false # 2 is not in the array + # assert [1..2].has_exactly([3,1,2]) == false # 3 is not in the range + # + # Repeated elements must be present in both collections in the same amount. + # So basically it is a multi-set comparison. + # + # assert [1,2,3,2].has_exactly([1,2,2,3]) == true # the same elements + # assert [1,2,3,2].has_exactly([1,2,3]) == false # more 2 in the first array + # assert [1,2,3].has_exactly([1,2,2,3]) == false # more 2 in the second array + # + # Note that the default implementation is general and correct for any lawful Collections. + # It is memory-efficient but relies on `count` so may be CPU-inefficient for some kind of collections. + fun has_exactly(other: Collection[E]): Bool + do + if length != other.length then return false + for e in self do if self.count(e) != other.count(e) then return false + return true + end end -# Instances of the Iterator class generates a series of elements, one at a time. -# They are mainly used with collections. +# Iterators generate a series of elements, one at a time. +# +# They are mainly used with collections and obtained from `Collection::iterator`. interface Iterator[E] # The current item. # Require `is_ok`. @@ -174,7 +212,7 @@ end # # Used to pass arguments by reference. # -# Also used when one want to give asingle element when a full +# Also used when one want to give a single element when a full # collection is expected class Container[E] super Collection[E] @@ -276,7 +314,7 @@ end # # ... # s.add(a) # assert s.has(b) == true -interface Set[E: Object] +interface Set[E] super SimpleCollection[E] redef fun has_only(item) @@ -348,7 +386,7 @@ interface Set[E: Object] end # MapRead are abstract associative collections: `key` -> `item`. -interface MapRead[K: Object, V] +interface MapRead[K, V] # Get the item at `key` # # var x = new HashMap[String, Int] @@ -387,7 +425,14 @@ interface MapRead[K: Object, V] return default end - # Alias for `keys.has` + # Is there an item associated with `key`? + # + # var x = new HashMap[String, Int] + # x["four"] = 4 + # assert x.has_key("four") == true + # assert x.has_key("five") == false + # + # By default it is a synonymous to `keys.has` but could be redefined with a direct implementation. fun has_key(key: K): Bool do return self.keys.has(key) # Get a new iterator on the map. @@ -437,6 +482,49 @@ interface MapRead[K: Object, V] # Note: the value is returned *as is*, implementations may want to store the value in the map before returning it # @toimplement protected fun provide_default_value(key: K): V do abort + + # Does `self` and `other` have the same keys associated with the same values? + # + # ~~~ + # var a = new HashMap[String, Int] + # var b = new ArrayMap[Object, Numeric] + # assert a == b + # a["one"] = 1 + # assert a != b + # b["one"] = 1 + # assert a == b + # b["one"] = 2 + # assert a != b + # ~~~ + redef fun ==(other) + do + if not other isa MapRead[nullable Object, nullable Object] then return false + if other.length != self.length then return false + for k, v in self do + if not other.has_key(k) then return false + if other[k] != v then return false + end + return true + end + + # A hashcode based on the hashcode of the keys and the values. + # + # ~~~ + # var a = new HashMap[String, Int] + # var b = new ArrayMap[Object, Numeric] + # a["one"] = 1 + # b["one"] = 1 + # assert a.hash == b.hash + # ~~~ + redef fun hash + do + var res = length + for k, v in self do + if k != null then res += k.hash * 7 + if v != null then res += v.hash * 11 + end + return res + end end # Maps are associative collections: `key` -> `item`. @@ -463,7 +551,7 @@ end # assert map.values.has(1) == true # assert map.values.has(3) == false # -interface Map[K: Object, V] +interface Map[K, V] super MapRead[K, V] # Set the `value` at `key`. @@ -523,7 +611,7 @@ interface Map[K: Object, V] end # Iterators for Map. -interface MapIterator[K: Object, V] +interface MapIterator[K, V] # The current item. # Require `is_ok`. fun item: V is abstract @@ -554,7 +642,7 @@ interface MapIterator[K: Object, V] end # Iterator on a 'keys' point of view of a map -class MapKeysIterator[K: Object, V] +class MapKeysIterator[K, V] super Iterator[K] # The original iterator var original_iterator: MapIterator[K, V] @@ -565,7 +653,7 @@ class MapKeysIterator[K: Object, V] end # Iterator on a 'values' point of view of a map -class MapValuesIterator[K: Object, V] +class MapValuesIterator[K, V] super Iterator[V] # The original iterator var original_iterator: MapIterator[K, V] @@ -912,7 +1000,7 @@ end # Associative arrays that internally uses couples to represent each (key, value) pairs. # This is an helper class that some specific implementation of Map may implements. -interface CoupleMap[K: Object, V] +interface CoupleMap[K, V] super Map[K, V] # Return the couple of the corresponding key @@ -934,12 +1022,14 @@ interface CoupleMap[K: Object, V] return c.second end end + + redef fun has_key(key) do return couple_at(key) != null end # Iterator on CoupleMap # # Actually it is a wrapper around an iterator of the internal array of the map. -private class CoupleMapIterator[K: Object, V] +private class CoupleMapIterator[K, V] super MapIterator[K, V] redef fun item do return _iter.item.second