Collections are Java classes developed to efficiently store multiple elements of a certain type. Unlike Java arrays collections can store any number of elements. The simplest collection is ArrayList, which you can treat as a resizable array. The following line of code creates an (initially empty) ArrayList of objects of class Person:
ArrayList<Person> friends = new ArrayList<Person>();
Note that the type of the collection includes the element type in angle brackets. This "tunes" the collection to work with the specific element type, so that, for example, the function get() of friends will return object of type Person. The ArrayList<Person> offers the following API (for the complete API see Java Class Reference):
The following code fragment tests if the friends list contains the person victor and, if, victor is not in there, adds him to the list:
if( ! friends.contains( victor ) )
friends.add( victor );
All collection types support iteration over elements. The simplest construct for iteration is a "for" loop. Suppose the class Person has a field income. The loop below prints all friends with income greater than 100000 to the model log:
for( Person p : friends ) {
if( p.income > 100000 )
traceln( p );
}
Another popular collection type is LinkedList.
Consider a model of a distributor that maintains a backlog of orders from retailers. Suppose there is an
Order
class with the
amount
field. The backlog (essentially a FIFO queue) can be modeled as:
LinkedList supports functions common to all collections (like size() or isEmpty()) and also offers a specific API:
When a new order is received by the distributor it is placed at the end of the backlog:
backlog.addLast( order );
Each
time the inventory gets replenished, the distributor tries to ship the
orders starting from the head of the backlog. If the amount in an order
is bigger than the remaining inventory, the order processing stops. The
order processing can look like this:
while( ! backlog.isEmpty() ) { //repeat the code below while the backlog is not empty
Order order = backlog.getFirst(); //pick the first order in the backlog
if( order.amount <= inventory ) { //if enough inventory to satisfy this order
ship( order ); //ship
inventory -= order.amount; //decrease available inventory
backlog.removeFirst(); //remove the order from the backlog
} else { //not enough inventory to ship
break; //stop order backlog processing
}
}
We recommend to declare collections in agents and experiments graphically. The
Collection
object is located in the
Agent
palette. All you need to do is to drop it on the canvas and choose the
collection and the element types. At runtime you will be able to view
the collection contents by clicking its icon.
Declaring Java collection graphically
Different types of collections have different time complexity of operations. For example, checking if a collection of 10,000,000 objects contains a given object may take 80 milliseconds for ArrayList, 100 milliseconds for LinkedList, and less than 1 millisecond for HashSet and TreeSet. To ensure maximum efficiency of the model execution you should analyze, which operations are most frequent and choose the collection type correspondingly. The Table below contains the time complexities of the most common operations for four collection types.
Operation |
ArrayList |
LinkedList |
HashSet |
TreeSet |
Obtain size |
Constant |
Constant |
Constant |
Constant |
Add element |
Constant |
Constant |
Constant |
Log |
Remove given element |
Linear |
Linear |
Constant |
Log |
Remove by index |
Linear |
Linear |
– |
– |
Get element by index |
Constant |
Linear |
– |
– |
Find out if contains |
Linear |
Linear |
Constant |
Log |
The terms constant, linear, and logarithmic complexity mean the following. Linear complexity means that the worst time required to complete the operation grows linearly as the size of the collection grows. Constant means that it does not depend on the size at all, and Log means the time grows as the logarithm of the size. You should not treat the constant complexity as the unconditionally best choice. Depending on the size, different types of collection may behave better than others.
Consider the Figure. It may well happen that with relatively small number of elements the collection with linear complexity will behave better than the one with constant complexity.
Depending on the size, different types of collections may behave better that others
And a couple of things you should keep in mind when choosing the collection type:
When you declare an embedded agent as replicated, AnyLogic creates a special type of collection to store the individual agents. You have two options:
The options for the type of collection appear in the Advanced section of the embedded object properties, see the Figure.
Options for collection type of a replicated object
Both collections support functions like
size(),
isEmpty(),
get( int index ),
contains( Object ao ),
and iteration. If index is not specifically needed during iteration, it
is always better to use the enhanced form of "for" loop:
for( Person p : people ) {
…
}