(How)
C^# You Are - 9 March 2008
This week's questions are related to collections and lists of items.
For the examples assume an Employee class representing an employee.
The Employee class has an Id property representing the unique
identifier of the employee. The employee's name is represented through the
Name property. The Department class represents a department
and contains a list of employees in the department. An employee can be in
more than one department.
- You want to display the identifiers of the employees in a department as a
comma separated list. How can you do that? Answer
The straightforward answer is to either use the foreach statement to build the list manually or use the List<T>.ForEach
method with a delegate.
string GetEmployees ( )
{
string str = null;
foreach(Employee emp in Employees)
{
str = (str != null) ? str + ", " + emp.Id.ToString() :
emp.Id.ToString();
};
return str;
}
If .NET v3.5 is being used then the new extension method Aggregate
available to IEnumerable<T> objects can be used. This method takes
an enumerable list, calls a delegate for each element and returns a single
result. An overload allows for specifying the initial value. While
the delegate is not pretty, the rest of the code is pretty straightforward.
string GetEmployee()
{
return Employees.Aggregate(null, (str, emp) => (str != null) ? str + ", " +
emp.Id.ToString() : emp.Id.ToString());
}
- The department exposes functionality to add multiple employees at once. You need to filter out
objects with empty or null
names. How can you do that? Answer
The fastest method is to use the List<T>.RemoveAll method. This
method takes a predicate (a method that accepts the object and returns true or
false). If the predicate returns true then the item is removed. The
original list is modified.
void AddEmployees
( List<Employee> employees )
{
List<Employee> newList = new List<Employee>(employees);
newList.RemoveAll(RemoveEmptyEmployees);
}
static bool RemoveEmptyEmployees ( Employee item )
{
return String.IsNullOrEmpty(item.Name);
}
- You want to retrieve the employees of a departmen sorted by their id or
name. How can you do this efficiently without duplicating too much data? Answer
The SortedList and SortedDictionary are useful for these scenarios.
For more complex sorting or when the key does not support hash codes you can use
the KeyedCollection<T> class instead.
- Other areas of the application need to know when the department employees
change. How can you implement this? Answer
When notification is necessary then eventing is the way to go. For most classes you should use the
INotifyPropertyChanged interface. For collections there are a few
additional options. Prior to v3.5 the BindingCollection<T> class
can be used for automatic notification when the collection changes. This
type is predominantly for data binding though so it is not always appropriate.
For v3.5 and later the ObservableCollection<T> class can be used.
While serving the same basic function as the binding collection, the observable
collection is a little nicer fit for business objects.
- What is the difference between Hashtable and HybridDictionary? Answer
These are old-style collections but they are still pretty prevalent. The
HybridDictionary is the better of the two collections in most cases.
The HybridDictionary uses a linked-list dictionary for small collections.
When the dictionary gets too large it switches to a hash table.
Linked lists are more efficient for small collections but not for larger.
The HybridDictionary takes advantage of this. The only real
downside is the overhead when it transitions from the linked list to the hash
table.
The Hashtable is strictly a dictionary and therefore, while not as
efficient for small collections, performs well in normal cases.
- You are adding functionality to allow the merging of departments. You do
not want to add an employee if they are already a member of the new department.
How can you do this? Answer
You can do this manually and most people will. A new class in v3.5,
HashSet<T>, allows for set-based operations. The nice feature of this
class is that you can get the union or intersection of two sets of objects.
In the case of this example you could store one department's employees in a set.
The Union or UnionWith methods can then be used to get the
combined sets. Sets, by mathematical definition, only allow a single copy
of a value (like a dictionary). This ensures that the union returns only
unique employees. The methods accept a comparer to allow for custom comparison.
void MergeDepartment ( Department department )
{
HashSet<Employee> current = new HashSet<Employee>(Employees);
IEnumerable<Employee> newList = current.Union(department.Employees, EmployeeCompare);
...
}