This problem has two parts. In the first part, you will implement a class called Container. In the second part (described below), you will implement some functions with containers as parameters. You are provided a test file called testcontainer.py to test your code for this problem, which you can do by typing python3 testcontainer.py at the command line.
A Container object is an object that stores an unordered collection of items. You will implement this class in a module called problem1a.py. An item may occur several times in a container. Note than a container may contain an arbitrary collection of objects (for example, a container may contain integers, strings, lists, or other objects). You are asked to implement the following methods for the Container class (recall that all methods have self as the first parameter):
1. __init__ : The constructor creates an empty container. We store the contents of the container in a list. Hence, the constructor will simply create an instance attribute and initialize it as an empty list.
2. insert: This method has a single parameter item which is inserted into the container.
3. erase_one: This method has a single parameter item. One occurrence of item is deleted from the container. Recall that since the items in a container are unordered, it doesn't matter which occurrence is deleted. The container remains unchanged if item does not occur in the container.
4. erase_all: This method has a single parameter item. All occurrences of item are deleted from the container.
5. count: This method has a single parameter item. The number of occurrences of item in the container is returned.
6. items: This method has no parameters. A list of the distinct items in the container is returned. For example, if a container C has the items 1, "abc", 1, 2, 3, [4,5,6], 2, "abc", [4], [4,5,6], then C.items() should return 1, "abc", 2, 3, [4,5,6],[4]. The order of items in the returned list does not matter.
7. __str__: Returns a string representation of the container. Recall that the return value must be a string. Make sure that multiple occurrences of the same item appear consecutively in the returned string. Other than that, the order of the items does not matter. Note that you cannot sort the list, since it is an arbitrary collection of items which may not be comparable.
8. __repr__: Also returns a printable representation of the container.
9. __getitem__: This method overloads the [] (index) operator. If idx is the parameter to the index operator, __getitem__ must return the idx-th element of the container. If there are N items in the container, the valid values for idx are 0, 1, 2, ..., N - 1.
10. __add__: This method overloads the + operator and returns the "sum" of two containers. The sum of two containers is a new container that contains all the items of the two operand containers. Hence, if A is a container with items 1, 2, "abc", 2, [4] and B is a container with items 3, 2, 4, "abcd", [4], "xy", then A + B is the container with items 1, 2, "abc", 2, [4], 3, 2, 4, "abcd", [4], "xy". Keep in mind that the actual parameters should not be modified by this method.
11. __sub__: This method overloads the - operator and returns the "difference" of two containers. The difference of two containers A and B is a new container that contains only those items in A that do not occur in B. For example, if A and B are as shown in the example above, then A - B is the container 1, "abc", and B - A is the container 3, 4, "abcd", "xy". Again, the actual parameters should not be modified by this method.
12. __mul__: This method overloads the * operator and returns the "intersection" of two containers. The intersection of two containers A and B is a new container that contains items that are common to A and B. Note that the count of an item in the intersection is the minimum of the counts of that item in each of A and B. For example, if A and B are as shown in the example above, then A * B is the container with items 2, [4]. Again, the actual parameters should not be modified by this method.
After completing the above class implementation, you are asked to implement some functions that have containers as parameters and possibly as return values. Implement these functions in a module called problem1b.py. On the first line of this module, import the Container class from the problem1a module.
The following functions manipulate container objects. The Container class methods provide the interface required to manipulate objects of that class (the idea of encapsulation discussed in class), and you must use container methods to implement these functions. Do not manipulate container instance attributes directly (you will not be able to if instance attribute are made private, as you are asked to do).