lib/collections: add `Collection::has_exactly`
[nit.git] / lib / standard / collection / abstract_collection.nit
index 22a6563..fa16295 100644 (file)
@@ -123,17 +123,48 @@ interface Collection[E]
                return iterator.item
        end
 
-       # Is the collection contains all the elements of `other`?
+       # Does the collection contain at least each element of `other`?
        #
-       #    assert [1,1,1].has_all([1])         == true
-       #    assert [1,1,1].has_all([1,2])       == 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
+       #
+       # 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.
        fun has_all(other: Collection[E]): Bool
        do
                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.
@@ -334,6 +365,10 @@ interface Set[E: Object]
                return nhs
        end
 
+       # Returns a new instance of `Set`.
+       #
+       # Depends on the subclass, mainly used for copy services
+       # like `union` or `intersection`.
        protected fun new_set: Set[E] is abstract
 end