SlideShare a Scribd company logo
1 of 28
Nico Ludwig (@ersatzteilchen)
Collections – Part IV
2
●
Collections – Part IV
– Object-based vs. generic Collections
●
Generics Types in Java
– Sequential and associative Collections
– Associative Collections
●
Equivalence-based associative Collections: .Net's SortedDictionary
●
Operations on .Net's IDictionarys
●
Comparison and Implementation of .Net's Interfaces IComparable and IComparer
TOC
3
●
Explicitly typed – i.e. typenames must be explicitly written at their declaration:
●
Safely typed – i.e. unrelated types can't fool the compiler.
– Cross casting and other pointer stuff is generally illegal.
●
Statically typed – i.e. variables' types are determined at compile time:
●
Sorry? But the same variable can hold different sub type objects at run time!
– Indeed! We can define variables that may hold e.g. any derived type:
– .Net differs the static (Object) and the dynamic type (Car) of an instance.
– The idea of static/dynamic types is used for run time polymorphism in .Net.
double sum = 5.2; // Type name "double" must be explicitly written for the variable sum.
int count = 42; // count is of type int, we can only perform int operations on it!
Object o = new Car(); // Type Car is derived from type Object.
The Type System in .Net 1 (presented in C#1) – Part I
4
●
Esp. object-based collections rely on the cosmic hierarchy of .Net's type system: everything is an Object:
– .Net 1 collections: Hold items of static type Object, their dynamic types can vary.
●
In fact collections must be able to hold any type in order to be versatile.
– .Net 1 "resorted" to run time polymorphism (i.e. Liskov Substitution Principle (LSP)) to get this versatility.
– So in a .Net 1 collection, objects of any dynamic type can be stored.
●
Object-based collections work great, as long as...
– we'll only store objects of dynamic types that dependent code awaits,
– we'll only cast down to dynamic types that dependent code put in,
– we'll never put mixed unrelated dynamic types into the same collection,
– well as we don't fall into a type problem during run time.
ArrayList lines = new ArrayList(File.ReadAllLines("/Library/Logs/Software Update.log")); // File.ReadAllLines() was introduced with .Net 2!
object item1 = lines[0];
object item2 = lines[1];
// We have to use cast contact lenses to get the dynamic types out of the objects:
string text1 = (string)item1;
// Access string's interface:
int result = text1.IndexOf('g');
// We can also cast directly from the index notation:
string text2 = (string)lines[1];
The Type System in .Net 1 (presented in C#1) – Part II
5
●
The problem or lack in the type system using LSP can be presented with the just created collection lines:
●
The problem is that we as programmers have to know about the contained dynamic types (strings and not Cars in
lines).
– Whenever Object is used in an interface (the return value of lines' indexer), some convention must be around.
– This convention describes the dynamic type, we're really dealing with (strings and not Cars).
– The contributed programers have just to obey the convention... ;-)
●
We as programmers have to cast down (or unbox) to the type we await.
– The cast is needed to access the interface of a static type (e.g. car.StartEngine()).
– These casts indicate that the programer knows more than the compiler!
– The compiler wears "cast contact lenses"; it can't type check, it trusts the programmer!
– These casts are type checked at run time, so they are consuming run time!
– Type errors (an item of lines was casted to Car instead of string) will happen at run time, not at compile time.
object item1 = lines[0];
// But, these are not the awaited types, we can't deal with Cars, we await strings!
// This cast will fail! An InvalidCastException will be thrown!
Car car = (Car)item1;
car.StartEngine();
public class Car {
public void StartEngine() {
/* pass */
}
}
The Type System in .Net 1 (presented in C#1) – Part III
6
●
Object-based collections have an interesting feature: we can be heterogeneous collections:
– In a heterogeneous collection every item can have any different dynamic type:
●
It works, but heterogeneous collections are tricky: developers need to know, on which indexes objects of certain types
reside.
●
Heterogenous collection should be avoided! Strive to using homogenous collections or other solutions!
ArrayList objects = new ArrayList();
// Since each item is of type object, we can add any object to an ArrayList:
objects.Add("aString"); // String
objects.Add(42); // int
objects.Add(new object()); // object
objects.Add(new [] {1, 2, 3, 4}); // int[]
foreach(object item in objects) {
Console.WriteLine(item);
}
// This statement will fail, we can't deal with string, on index 1 an int was stored!
// An InvalidCastException will be thrown!
string result = (string)objects[1];
Homogeneous and heterogeneous Collections
7
●
What could we do close the lack in the .Net 1 type system to stay typesafe?
●
We could use strictly typed arrays as collections if possible, they're not object-based and therefore typesafe:
– However, arrays can not be used, when the collection in question needs to be modified (enlarged or downsized) after creation.
●
We could create own, typesafe not object-based collections as UDTs (e.g. a special string-list for the discussed example).
– In .Net we could resort to so called specialized collections in the namespace System.Collections.Specialized, e.g. StringCollection.
●
But in the world of collections, there is a much better way to work in a typesafe manner: generic collections!
// Create an array that hold strings:
string[] lines = File.ReadAllLines("/Library/Logs/Software Update.log"));
// With arrays we don't need casts, instead we can directly access lines' items as string objects:
string text1 = lines[0];
// Access string's interface:
int result = text1.IndexOf('g');
// Create a specialized StringCollection:
StringCollection lines = new StringCollection();
lines.AddRange(File.ReadAllLines("/Library/Logs/Software Update.log"));
// With the specialized StringCollection we don't need casts, instead we can directly access lines' items as string objects:
string text1 = lines[0];
// Access string's interface:
int result = text1.IndexOf('g');
The Type System in .Net 1 – Some Remedy
8
●
Let's improve our problematic code with the generic collection List<T>:
●
.Net 2 introduced generic types to get rid of the presented type problems.
– Generic types are types that leave a part of their type information open.
– Generics are an outstanding feature in .Net 2.
●
Generics (here List<T>) leave type information open? How should this help me out?
– The open type information is accessible by type parameters (here T).
– As programmers we can fill the type parameters by concrete type arguments (here string).
– By setting type arguments of a generic type we create another type, the constructed type (List<string> in this case).
●
The full name of the constructed type is List<string>!
– => Net effect: The type argument (string) will be of static type, so the formerly open type information can be checked by the compiler.
– In the end typesafety means that types are checked by the compiler at compile time and no longer at run time.
// Create a generic List that holds strings:
List<string> lines = new List<string>(File.ReadAllLines("/Library/Logs/Software Update.log"));
// This time we don't need casts, instead we can directly access lines' items as string objects:
string text1 = lines[0];
// Access string's interface:
int result = text1.IndexOf('g');
// The generic type List<T>:
public class List<T> { // (members hidden)
public void Add(T item) {
/* pass */
}
}
// This time we'll get a compile time error:
Car car1 = lines[1];
// The type argument in lines was string, not Car!
// Cannot convert string to Car.
car1.StartEngine();
Generics to the Rescue
9
●
.Net's generic collections live in the namespace System.Collections.Generic.
●
The generic counterpart of the collection ArrayList is List<T>, T is the type parameter.
– List<T>'s interface is set to the open type T in parameter- and return-types of methods.
– The type parameter T acts as a placeholder for the actual type argument.
●
When a type is constructed, T is replaced by a type argument (the result is the constructed type).
– List<string>'s interface is set to the static type string in parameter- and return- types of methods.
●
The idea of generics is to use types (i.e. not values) as arguments!
– The typesafty we got is that generics move type run time errors to compile time errors.
// The generic type List<T>:
public class List<T> { // (details hidden)
public void Add(T item) { /* pass */ }
public List<T> GetRange(int index, int count) { /* pass */ }
}
// The constructed type List<string> has following interface:
public class List<string> { // (details hidden)
public void Add(string item) { /* pass */ }
public List<string> GetRange(int index, int count) { /* pass */ }
}
// Create a generic List that holds strings:
List<string> lines;
List
T
The UML represents generic
types as parameterized classes.
Generics – Overview
List<T -> string>
«bind»
<T -> string>
List<string>
implicit binding against a type
argument
explicit binding against a type
argument
10
●
It is also possible to define generic types, whose type argument is another generic type.
– E.g. we can define a list of lists, i.e. a collection of collections, which is effectively a two-dimensional array or matrix.
– Such collections are better than multidimensional arrays in some aspects:
●
They offer the same concept to express rectangular as well as jagged arrays.
●
"Real" collections are very flexible, as elements can be added and removed (or: the matrix' dimensions can be enlarged and shrank).
●
The .Net framework as well as Java do also support generic types having two or more type parameters:
– E.g. with the type SortedDictionary<TKey, Tvalue> (this type will be discussed later):
●
To understand collections in Java, C++ and .Net it is required to understand also advanced generics.
// Creating a SortedDictionary object:
SortedDictionary<string, int> aDictionary = new SortedDictionary<string, int>();
aDictionary.Add("fortytwo", 42);
// The generic type SortedDictionary<TKey, TValue>:
public class SortedDictionary<TKey, TValue> { // (members hidden)
/* pass */
}
// A jagged array in C# as matrix:
int[][] matrix = new int[3][];
matrix[0] = new[] {1, 2, 3, 4};
matrix[1] = new[] {6, 7};
matrix[2] = new[] {8, 9, 0};
Console.WriteLine("Item: {0}", matrix[1][0]);
// >Item: 6
// A list of lists of int as matrix:
List<List<int>> matrix = new List<List<int>>();
matrix.Add(new List<int>{1, 2, 3, 4});
matrix.Add(new List<int>{6, 7});
matrix.Add(new List<int>{8, 9, 0});
Console.WriteLine("Item: {0}", matrix[1][0]);
// >Item: 6
Slightly advanced Generics
11
●
Hence, we'll use generic types whenever appropriate. We'll define following substitutes for already introduced collections:
– ICollection → ICollection<T>
– IList → IList<T>
– ArrayList → List<T>
– IEnumerable → IEnumerable<T>
– IEnumerator → IEnumerator<T>
– .Net's framework design guidelines suggest using only generic collection types in public interfaces.
●
From object-based to generic collections:
IList names = new ArrayList();
names.Add("James");
names.Add("Miranda");
// Get the values back (object-based collection: static type Object):
object name1 = names[0]; // "James"
object name2 = names[1]; // "Miranda"
string name1AsString = (string)name1; // Cast the string out of the object.
string name2As = (string)names[1]; // Cast directly from the index notation.
names[1] = "Meredith";
Console.WriteLine(names[1]);
// >Meredith
IList<string> names = new List<string>();
names.Add("James");
names.Add("Miranda");
// Get the values back (generic string-collection: static type string):
string name1 = names[0]; // "James"
string name2 = names[1]; // "Miranda"
names[1] = "Meredith";
Console.WriteLine(names[1]);
// >Meredith
The better Type System –
from object-based to generic Collections
12
●
C++ templates are, at least principally, C++' equivalent to .Net's and Java's generics.
– C++ provides the template std::vector<T> (<vector>), which is functionally equivalent to .Net's List<T>:
– Before C++ had templates, void*-based collections have been used, incl. cast contact lenses. - This is still true for C.
●
void*-based collections are the functional equivalent to object-based collections!
●
Objective-C and many scripting languages use so called dynamic typing instead of generic or object-based structures.
– (We're not going to discuss these concepts in this course.)
// names is a vector containing string-elements.
std::vector<std::string> names;
names.push_back("James");
names.push_back("Miranda");
// Get the values back (template string-container: static type std::string):
std::string name1 = names[0]; // "James"
std::string name2 = names[1]; // "Miranda"
names[1] = "Meredith";
std::cout<<names[1]<<std::endl;
// >Meredith
// in h-file <vector>
template <typename T> class vector { // (details hidden)
public:
void push_back(const T& newItem);
};
The Collection Type System of the C++ STL
13
●
The story about generic collections in Java is somewhat advanced, but Java programmers should know these facts.
– A good way to understand Java's generics (and the problems that come with it) is to compare them to, e.g., .Net's generics.
●
Here we have basically the same generic class in Java and C#:
– The definition of instances of these classes has almost the same syntax in Java and C#:
●
In Java we can only use reference types as type arguments for generic types. E.g. we can not create MyList<int> or MyList<double>.
– As we know the idea behind generics is to have typesafty. So the last statements won't compile respectively:
The Collection Type System on the Java Platform – Part I
// Java
public class MyList<T> {
public List<T> items = new ArrayList<T>(5);
}
// Java
stringList.items.add("Frank"); // OK for the compiler! A string literal can be set, because items is a List<String>.
stringList.items.add(42); // Invalid for the compiler! Generics are typesafe! An int literal can't be set, because items is not a List<Integer>.
MyList<String> stringList = new MyList<String>();
MyList<Integer> intList = new MyList<Integer>();
MyList<string> stringList = new MyList<string>();
MyList<int> intList = new MyList<int>();
// C#
public class MyList<T> {
public IList<T> items = new List<T>(5);
}
// C#
stringList.items.Add("Frank"); // OK for the compiler! See explanation for Java above.
stringList.items.Add(42); // Invalid for the compiler! See explanation for Java above.
14
●
The difference between Java and .Net is that different things are generated at compile time.
– A compiler creating .Net IL code will produce a so called constructed type for each "filled out" generic type in the code:
– A compiler creating Java bytecode will just erase the type argument and will fall back to an object-based type:
●
This compilation step is called type erasure. The resulting type (w/o generic type parameters) is called the raw type of the generic type.
●
Often this isn't a problem in Java, because compile time typesafety is fine, but it hurts the run time typesafety!
●
Ouch! But Java provides a means to reestablish run time typesafety: run time type checked collection wrappers.
The Collection Type System on the Java Platform – Part II
stringList.items.add("Frank"); // Ok as before!
((MyList)stringList).items.add(42); // Huh? Casting (cast contact lenses) to the raw type and adding an int: ok for compiler and at run time!
String itemAt1 = stringList.items.get(1); // Bang! Getting the int at the index one via the generic type: ok for the compiler but crashes at run time!
// java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
type construction of a .Net IL compiler
// Java
MyList<String> stringList = new MyList<String>();
MyList<Integer> intList = new MyList<Integer>();
public class MyList { // Raw type
public List items = new ArrayList(5);
}
type erasure of a Java bytecode compiler
// C#
MyList<string> stringList = new MyList<string>();
MyList<int> intList = new MyList<int>();
public class MyList<string> { // Constructed type
public IList<string> items = new List<string>(5);
}
public class MyList<int> { // Constructed type
public IList<int> items = new List<int>(5);
}
15
●
Java provides the class Collections with some static methods (simple factories) to create run time type checked collections.
– A present collection needs to be passed to Collections.checked...() and a new collection wrapping the passed one will be returned.
– Let's wrap MyList's encapsulated List to be a checked List with Collections.checkedList():
●
More simple factories can be found in the class Collections as static methods (checkedSet(), checkedMap() etc.).
– The return type of all of these simple factories are just interface types, the type checked implementations are always hidden.
– So the UML diagram of the relations between the contributing types looks like so:
●
Run time type checked wrappers were added to the JDK in order have compatibility w/ non-generic collections, retaining
compile time typesafty of generics and having run time typesafety.
– There is an initiative in the Java community to introduce generic types with constructed types into Java: reified generics.
– Mind that run time type checking is costly!
The Collection Type System on the Java Platform – Part III
stringList.items = Collections.checkedList(stringList.items, String.class); // Wrap items, so that it can only deal with strings at compile time.
stringList.items.add("Frank"); // Ok as before! It was already checked by the compiler.
((MyList)stringList).items.add(42); // Bang! An int can't be added to a list that is only allowed to contain Strings!
String itemAt1 = stringList.items.get(1); // Will not be reached at all!
<<interface>>
List
HiddenCheckedListImplementation
exposes implements
Collections
+ checkedList(list : List<T>, type : Class<T>) : List<T>
instantiates
T
16
●
Up to now, we discussed relatively simple indexed and sequential collections.
●
Besides indexed and sequential collections there also exist so called associative collections.
●
In opposite to indexed and sequential collections, associative collections inspect the stored objects.
– E.g. the indexed collection ArrayList just stores references to objects, but it does never, e.g., call methods on these objects.
●
For indexed and sequential collections the contained items are said to be transparent.
– Associative collections have to inspect stored objects for equivalence or equality in order to provide very mighty features.
●
Let's start by analyzing a problem, which can be solved with associative collections.
Indexed, sequential and associative Collections
17
●
Let's assume that we have to handle color names and figure out the belonging to HTML color codes:
●
Of course the task can be solved this way, but the solution is based on a possibly fragile assumption:
– The two separate arrays need to hold belonging to values at the same indexes!
– Basically we've to go through all items sequentially and compare (Array.IndexOf()).
– We say the association is index-based.
●
The presented algorithm is a so called lookup-algorithm (lookup).
– Lookups are used very often in programming.
– A problem of lookups is that separate collections (colorNames and htmlColorCode) need to be evaluated (like tables in relational databases).
– Modern collection frameworks provide dedicated collections to cover lookups in a comfortable manner: associative collections.
// C#
// Here we have two arrays that hold color names and HTML color codes:
string[] colorNames = {"Blue", "Red", "Green"} ;
int[] htmlColorCodes = {0x0000FF, 0xFF0000, 0x00FF00};
// With the information given, the task to pick an HTML color code from a color name is trivial: Because the
// index of the color name matches the index of the color HTML code, we can formulate a simple algorithm:
int indexOfRed = Array.IndexOf(colorNames, "Red");
int colorCodeOfRed = htmlColorCodes[indexOfRed];
Console.WriteLine("Color code for Red: {0:X6}", colorCodeOfRed);
// >Color code for Red: FF0000
colorNames0x0000FF 0xFF0000 0x00FF00
"Blue" "Red" "Green" htmlColorCodes
210 matching indexes
Example – Color Names to HTML Color Codes – Part I
18
colorNamesToColorCodes
●
Associative collections abstract the usage of multiple collections to solve the just presented lookup in an intuitive manner:
– Here .Net's associative collection SortedDictionary<string, int> is shown (it implements IDictionary<string, int>):
– The association of both, color names and color codes, is available via the single collection colorNamesToHtmlColorCodes.
●
We have to rethink our termination: associative collections associate a key (color name) to a value (color code).
– The association is key-based and no longer index-based.
– The internal "organization" is key-value-pair-based.
– In a sense an array is nothing but an associative collection that associates a value with an index (mind the []-syntax).
– In fact real problems often involve associating values with other values, e.g.: White pages, thesaurus, document index.
●
The .Net collection KeyedCollection<K, T> allows the lookup of data stored in the value (i.e. there are no key-value-pairs).
// Associating color names with HTML color codes using a SortedDictionary:
IDictionary<string, int> colorNamesToColorCodes = new SortedDictionary<string, int>();
colorNamesToColorCodes.Add("Blue", 0x0000FF);
colorNamesToColorCodes.Add("Red", 0xFF0000);
colorNamesToColorCodes.Add("Green", 0x00FF00);
int colorCodeOfRed = colorNamesToColorCodes["Red"];
Console.WriteLine("Color code for Red: {0:X6}", colorCodeOfRed);
// >Color code for Red: FF0000
0x0000FF 0xFF0000 0x00FF00
"Blue" "Red" "Green"
Key-value-pair
{"Green", 0x00FF00}
Example – Color Names to HTML Color Codes – Part II
19
●
In many scripting languages associative collections have special syntactical support.
– The names "hash", "hashmap" or "associative array" are common in scripting languages.
– In JavaScript every object is a collection of property-value-pairs per se. An array is also an associative collection:
●
In other platforms associative collections are often called Maps (Java) or Dictionaries (Cocoa, .Net).
– Esp. the term "Map" is taken from the phrase "to map something", which means "to associate something".
– The term "hash" still needs to be clarified in this context: we have to understand how associative collections work.
●
We'll start discussing equivalence-based associative collections and then equality-based associative collections using hashing.
# E.g. in Ruby associative collections are supported as "hashes" with integrated syntactical support.
# Just initialize a variable with a list of key => value pairs:
colorNamesToColorCodes = {"Blue" => 0x0000FF, "Red" => 0xFF0000, "Green" => 0x00FF00}
# The items can be accessed with the []-operator:
printf("Color code for Red: %06X", colorNamesToColorCodes["Red"])
# >Color code for Red: FF0000
// JavaScript
// Create associative collection as object with properties:
var colorNamesToColorCodes = new Object();
colorNamesToColorCodes.Blue = 0x0000FF;
colorNamesToColorCodes.Red = 0xFF0000;
colorNamesToColorCodes.Green = 0x00FF00;
console.log("Color code for Red: "
+colorNamesToColorCodes.Red.toString(16));
// >Color code for Red: FF0000
// JavaScript
// Create associative collection as associative array:
var colorNamesToColorCodes = new Object();
colorNamesToColorCodes["Blue"] = 0x0000FF;
colorNamesToColorCodes["Red"]= 0xFF0000;
colorNamesToColorCodes["Green"]= 0x00FF00;
console.log("Color code for Red: "
+colorNamesToColorCodes["Red"].toString(16));
// >Color code for Red: FF0000
Associative Collections in other Languages
20
●
New about associative collections is that associative collections inspect the items they hold.
– I.e. associative collections operate on contained items: they call methods on the keys of the contained key-value-pairs.
– Associative collections need to compare the keys they hold.
– In opposite to other collections, items are got and set by analyzing their relationships.
●
Associative collections are very powerful and allow writing elegant/readable algorithms to solve complicated problems.
– Associative collections could be implemented with two arrays as shown before, but this would be inefficient for common cases.
– A clever internal organization of associative collections is required to allow efficient access and modification of contained items.
●
There are two general ways to organize items (i.e. their keys) in an associative collection:
– (1) By equivalence. I.e. by their relative order/order-relationship, such as less than and greater than.
– (2) By equality. I.e. by hash-codes and the result of the equality check (methods hashCode()/equals() (Java) or
GetHashCode()/Equals() (.Net)).
●
In this and the next lecture we're going to discuss associative collections that organize their keys by equivalence.
– This is the case for SortedDictionary, so we'll discuss .Net's SortedDictionary.
Organization of Items in associative Collections
21
●
Create the empty SortedDictionary<K, V> colorNamesToColorCodes:
●
Then we can add three key-value-pairs like so:
●
Get the value of a key, i.e. make a lookup with the indexer ([]-operator):
●
Check, whether an entry with a certain key is already existing with the method ContainsKey():
●
Iteration: The internal organization is key-value-pair-based, so IDictionary's iterator produces an iterator of key-value pairs.
C# – collection initializers for dictionaries
// Apply a collection initializer on a SortedDictionary:
IDictionary<string, int> colorNamesToColorCodes2 = new SortedDictionary<string, int> {
{"Blue", 0x0000FF}, {"Red", 0xFF0000}, {"Green", 0x00FF00}
};
IDictionary<string, int> colorNamesToColorCodes = new SortedDictionary<string, int>();
colorNamesToColorCodes.Add("Blue", 0x0000FF);
colorNamesToColorCodes.Add("Red", 0xFF0000);
colorNamesToColorCodes.Add("Green", 0x00FF00);
int valueForBlue = colorNamesToColorCodes2["Blue"];
// >0x0000FF
Operations on IDictionarys – Part I
// IDictionary<string, int> implements IEnumerable<KeyValuePair<string, int>>.
// Iteration yields KeyValuePair<string, int>-items:
foreach (KeyValuePair<string, int> item in colorNamesToColorCodes) {
Console.WriteLine(item);
}
bool blueAlreadyPresent = colorNamesToColorCodes2.ContainsKey("Blue");
// >true
22
●
Trying to query the value for a key that doesn't exist will throw a KeyNotFoundException:
– To avoid these "surprises" check the key for existence (with ContainsKey()), before it is looked up.
●
Adding a pair for an already existing key will throw an ArgumentException.
– .Net dictionaries don't allow having a key with multiple values. (However, the C++' STL-container std::multimap can handle this.)
●
The indexer allows adding new entries as well as replacing values of existing key-value-pairs and reading values:
●
We can get the current count of elements stored in the dictionary (Count is required by implementing ICollection<T>):
colorNamesToColorCodes.Add("Blue", 17); // Throws ArgumentException: a key-value-pair with the same key already exists in the dictionary.
colorNamesToColorCodes["Blue"] = 17; // OK! Replaces "Blue"'s value 0x0000FF with 17.
colorNamesToColorCodes["Yellow"] = 0xFFFF00; // Adds the new key-value-pair {"Yellow", 0xFFFF00}.
if (colorNamesToColorCodes.ContainsKey("Yellow")) { // Checking the existence of the key "Yellow".
// Use the indexer to retrieve "Yellow"'s value:
Console.WriteLine("Color code for Yellow: {0:X6}", colorNamesToColorCodes["Yellow"]);
// >Color code for Yellow: FFFF00
}
Console.WriteLine(colorNamesToColorCodes.Count);
// >4
Operations on IDictionarys – Part II
int valueForOrange = colorNamesToColorCodes2["Orange"]; // Throws KeyNotFoundException: a key-value-pair with that key doesn't exists in the dictionary.
23
●
Now its time to understand how SortedDictionarys work basically, we'll discuss it in depth in the next lecture.
– We have to clarify, how SortedDictionary knows if a key is already present or not! - It needs to compare keys somehow!
●
The question is: "How does SortedDictionary know if two keys are equal?"
– A part of the answer is that SortedDictionary doesn't know, if two items are equal, but it knows if two items are equivalent!
– SortedDictionary's comparison is based on the order-relationship among items. This is called equivalence comparison.
●
The order-relationship can be expressed by evaluating two values one being less than, greater than or equal the other.
– If of two values one is neither less than nor greater than the other the values are said to be equivalent (Not equal!).
– .Net provides a way for types to declare equivalence comparability: implementing the interface IComparable/IComparable<T>.
– (The C++ STL requires types to override operator< to implement equivalence comparability.)
●
Now we are going to understand how IComparable/IComparable<T> has to be implemented for own UDTs.
SortedDictionary and Equivalence Comparison
24
UDTs as Keys of associative Collections – Part I
● Up to now we've only used objects of builtin types for the keys of associative collections (e.g. string).
– Now we are going to explore how to use keys of our own types. Let's do this with the UDT Car:
– Obviously it doesn't work this way! - What did we miss?
● The problem is that nobody (esp. SortedDictionary) knows, how to compare Cars!
– One way to implement this: Car could itself know, how it can be compared – we've to implement IComparable<Car> in Car:
– IComparable<T>.CompareTo() should return a value less than 0, if this < other, a value greater than 0, if this > other and otherwise 0.
● For Car we'll delegate the implementation of
IComparable<Car>.CompareTo() to Car's property
Name, Name is of type string (string implements
IComparable<string>).
– With this implementation of Car
SortedDictionary<TKey, TValue> works
as expected:
public class Car {
public string Name {get; set;}
}
IDictionary<Car, string> carToManufacturer = new SortedDictionary<Car, string>();
// Adding the first item won't require to compare items:
carToManufacturer[new Car{ Name = "Focus" }] = "Ford";
// Will throw ArgumentException: Object doesn't implement IComparable!
carToManufacturer[new Car{ Name = "Auris" }] = "Toyota";
IDictionary<Car, string> carToManufacturer = new SortedDictionary<Car, string>();
carToManufacturer[new Car{ Name = "Focus" }] = "Ford";
// OK!
carToManufacturer[new Car{ Name = "Auris" }] = "Toyota";
public class Car : IComparable<Car> { // (members hidden)
public int CompareTo(Car other) {
// Very simple implementation that compares the Cars' Name fields:
return this.Name.CompareTo(other.Name);
}
}
25
UDTs as Keys of associative Collections – Part II
● But there are cases, in which implementing IComparable<T> is no option to make types usable as keys:
– (1) if we can not modify the type in question, e.g. if it is a type of a 3rd
party library,
– (2) if the type in question does already implement IComparable<T>, but the implemented comparison doesn't meet our needs,
– (3) if the type doesn't implement IComparable<T> at all.
● Let's assume that we want to use Cars as keys by case insensitive comparison of their Name property.
– We could change the implementation of Car.CompareTo(), but this would hurt the Open-Close Principle (OCP).
– Effectively we have the case (2). The present implementation of IComparable<Car> doesn't meet our needs.
● To cover these cases there is another way to implement comparison: implement comparison in a different type (not in Car).
– I.e. we can implement a dedicated type that has only one responsibility: comparing Cars. Such a type is called comparator.
– The .Net framework provides a special interface to support such special comparison types: IComparer/IComparer<T>.
– Now it's time to implement a comparer to compare the case insensitive Name of Cars.
26
UDTs as Keys of associative Collections – Part III
● The type SortedDictionary<TKey, TValue> accepts an object of type IComparer<TKey> in one of its ctors:
– As can be seen the passed comparer refers to the type TKey.
● The comparer to specify in the ctor determines, how Cars are getting compared. The comparer looks like this:
● Here we'll finally pass an instance of the created CaseInsensitveCarComparer to SortedDictionary's ctor:
public class CaseInsensitiveCarComparer : IComparer<Car> {
public int Compare(Car lhs, Car rhs) {
// Very simple implementation that compares the Name
// fields of two Cars ignoring the case:
return string.Compare(lhs.Name, rhs.Name, true);
}
}
// The generic type SortedDictionary<TKey, TValue>:
public class SortedDictionary<TKey, TValue> { // (details hidden)
public SortedDictionary(IComparer<TKey> comparer);
}
// Create a dictionary and specify the special comparer in the ctor:
IDictionary<Car, string> carToManufacturer = new SortedDictionary<Car, string>(new CaseInsensitiveCarComparer());
carToManufacturer[new Car{ Name = "Cortina" }] = "Ford";
// This won't add another "cortina", because the specified comparer evaluates "Cortina" and "cortina" as being equivalent.
carToManufacturer[new Car{ Name = "cortina" }] = "Lotus"; // Will set "Cortina"'s value to "Lotus".
Console.WriteLine("Count of items: {0}", carToManufacturer.Count);
// >Count of items: 1
27
Controlling String-Key Comparison
● If we use strings as keys (i.e. not a UDT like Car), we can use predefined comparers to compare case insensitively.
– The .Net framework provides a set of predefined StringComparer objects in the type StringComparer.
– Let's rewrite the color code example for case insensitive color names:
– We can do the same with Java's TreeMap managing string-keys case-insensitively using a special Comparator:
– If we like to exploit the sorting of the Map and want the keys to be sorted in descending order, just reverse the Comparator:
// Create a dictionary and specify the case insensitive string comparer in the ctor:
IDictionary<string, int> colorNamesToColorCodes = new SortedDictionary<string, int>(StringComparer.OrdinalIgnoreCase);
colorNamesToColorCodes.Add("Green", 0x00FF00);
// Because of the case insensitive comparison "Green" and "green" are seen as equivalent key objects:
int colorCodeOfGreen = colorNamesToColorCodes["green"];
Console.WriteLine("Color code for Green: {0:X6}", colorCodeOfGreen);
// >Color code for Green: 00FF00
// Create a map and specify the case insensitive string comparator in the ctor:
Map<String, Integer> colorNamesToColorCodes = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
colorNamesToColorCodes.put("Green", 0x00FF00);
// Because of the case insensitive comparison "Green" and "green" are seen as equivalent key objects:
int colorCodeOfGreen = colorNamesToColorCodes.get("green");
System.out.printf("Color code for Green: %06X%n", colorCodeOfGreen);
// >Color code for Green: 00FF00
// Create a map and specify the case insensitive string comparator in the ctor, the sorting should be descending:
Map<String, Integer> colorNamesToColorCodesDescending =
new TreeMap<>(Collections.reverseOrder(String.CASE_INSENSITIVE_ORDER));
28
Thank you!

More Related Content

What's hot

Persistence And Documents
Persistence And DocumentsPersistence And Documents
Persistence And DocumentsSV.CO
 
Objective-C to Swift - Swift Cloud Workshop 3
Objective-C to Swift - Swift Cloud Workshop 3Objective-C to Swift - Swift Cloud Workshop 3
Objective-C to Swift - Swift Cloud Workshop 3Randy Scovil
 
C++ - Constructors,Destructors, Operator overloading and Type conversion
C++ - Constructors,Destructors, Operator overloading and Type conversionC++ - Constructors,Destructors, Operator overloading and Type conversion
C++ - Constructors,Destructors, Operator overloading and Type conversionHashni T
 
String & path functions in vba
String & path functions in vbaString & path functions in vba
String & path functions in vbagondwe Ben
 
Java 1.5 - whats new and modern patterns (2007)
Java 1.5 - whats new and modern patterns (2007)Java 1.5 - whats new and modern patterns (2007)
Java 1.5 - whats new and modern patterns (2007)Peter Antman
 
L9 wrapper classes
L9 wrapper classesL9 wrapper classes
L9 wrapper classesteach4uin
 
Learning core java
Learning core javaLearning core java
Learning core javaAbhay Bharti
 
standard template library(STL) in C++
standard template library(STL) in C++standard template library(STL) in C++
standard template library(STL) in C++•sreejith •sree
 
Stl (standard template library)
Stl (standard template library)Stl (standard template library)
Stl (standard template library)Hemant Jain
 
Standard Template Library
Standard Template LibraryStandard Template Library
Standard Template LibraryKumar Gaurav
 
Java core - Detailed Overview
Java  core - Detailed OverviewJava  core - Detailed Overview
Java core - Detailed OverviewBuddha Tree
 
5variables in c#
5variables in c#5variables in c#
5variables in c#Sireesh K
 

What's hot (20)

Persistence And Documents
Persistence And DocumentsPersistence And Documents
Persistence And Documents
 
Objective-C to Swift - Swift Cloud Workshop 3
Objective-C to Swift - Swift Cloud Workshop 3Objective-C to Swift - Swift Cloud Workshop 3
Objective-C to Swift - Swift Cloud Workshop 3
 
Quick Scala
Quick ScalaQuick Scala
Quick Scala
 
C++ - Constructors,Destructors, Operator overloading and Type conversion
C++ - Constructors,Destructors, Operator overloading and Type conversionC++ - Constructors,Destructors, Operator overloading and Type conversion
C++ - Constructors,Destructors, Operator overloading and Type conversion
 
String & path functions in vba
String & path functions in vbaString & path functions in vba
String & path functions in vba
 
Java 1.5 - whats new and modern patterns (2007)
Java 1.5 - whats new and modern patterns (2007)Java 1.5 - whats new and modern patterns (2007)
Java 1.5 - whats new and modern patterns (2007)
 
L9 wrapper classes
L9 wrapper classesL9 wrapper classes
L9 wrapper classes
 
#_ varible function
#_ varible function #_ varible function
#_ varible function
 
C++ STL 概觀
C++ STL 概觀C++ STL 概觀
C++ STL 概觀
 
Learning core java
Learning core javaLearning core java
Learning core java
 
standard template library(STL) in C++
standard template library(STL) in C++standard template library(STL) in C++
standard template library(STL) in C++
 
JVM and OOPS Introduction
JVM and OOPS IntroductionJVM and OOPS Introduction
JVM and OOPS Introduction
 
Stl (standard template library)
Stl (standard template library)Stl (standard template library)
Stl (standard template library)
 
Java Wrapper Classes and I/O Mechanisms
Java Wrapper Classes and I/O MechanismsJava Wrapper Classes and I/O Mechanisms
Java Wrapper Classes and I/O Mechanisms
 
Standard Template Library
Standard Template LibraryStandard Template Library
Standard Template Library
 
Variable
VariableVariable
Variable
 
Java core - Detailed Overview
Java  core - Detailed OverviewJava  core - Detailed Overview
Java core - Detailed Overview
 
5variables in c#
5variables in c#5variables in c#
5variables in c#
 
Java String
Java String Java String
Java String
 
Lesson3
Lesson3Lesson3
Lesson3
 

Similar to (4) collections algorithms

Typescript: Beginner to Advanced
Typescript: Beginner to AdvancedTypescript: Beginner to Advanced
Typescript: Beginner to AdvancedTalentica Software
 
(6) collections algorithms
(6) collections algorithms(6) collections algorithms
(6) collections algorithmsNico Ludwig
 
ActionScript 3.0 Fundamentals
ActionScript 3.0 FundamentalsActionScript 3.0 Fundamentals
ActionScript 3.0 FundamentalsSaurabh Narula
 
(2) collections algorithms
(2) collections algorithms(2) collections algorithms
(2) collections algorithmsNico Ludwig
 
Java Generics Introduction - Syntax Advantages and Pitfalls
Java Generics Introduction - Syntax Advantages and PitfallsJava Generics Introduction - Syntax Advantages and Pitfalls
Java Generics Introduction - Syntax Advantages and PitfallsRakesh Waghela
 
Chapter 1 Presentation
Chapter 1 PresentationChapter 1 Presentation
Chapter 1 Presentationguest0d6229
 
Effective Java Second Edition
Effective Java Second EditionEffective Java Second Edition
Effective Java Second Editionlosalamos
 
Java New Programming Features
Java New Programming FeaturesJava New Programming Features
Java New Programming Featurestarun308
 
(6) collections algorithms
(6) collections algorithms(6) collections algorithms
(6) collections algorithmsNico Ludwig
 
typescript.pptx
typescript.pptxtypescript.pptx
typescript.pptxZeynepOtu
 
Generics Collections
Generics CollectionsGenerics Collections
Generics Collectionsphanleson
 
(2) collections algorithms
(2) collections algorithms(2) collections algorithms
(2) collections algorithmsNico Ludwig
 
Abstract Data Types (a) Explain briefly what is meant by the ter.pdf
Abstract Data Types (a) Explain briefly what is meant by the ter.pdfAbstract Data Types (a) Explain briefly what is meant by the ter.pdf
Abstract Data Types (a) Explain briefly what is meant by the ter.pdfkarymadelaneyrenne19
 

Similar to (4) collections algorithms (20)

Typescript: Beginner to Advanced
Typescript: Beginner to AdvancedTypescript: Beginner to Advanced
Typescript: Beginner to Advanced
 
(6) collections algorithms
(6) collections algorithms(6) collections algorithms
(6) collections algorithms
 
ActionScript 3.0 Fundamentals
ActionScript 3.0 FundamentalsActionScript 3.0 Fundamentals
ActionScript 3.0 Fundamentals
 
(2) collections algorithms
(2) collections algorithms(2) collections algorithms
(2) collections algorithms
 
Java Generics Introduction - Syntax Advantages and Pitfalls
Java Generics Introduction - Syntax Advantages and PitfallsJava Generics Introduction - Syntax Advantages and Pitfalls
Java Generics Introduction - Syntax Advantages and Pitfalls
 
Chapter 1 Presentation
Chapter 1 PresentationChapter 1 Presentation
Chapter 1 Presentation
 
Effective Java Second Edition
Effective Java Second EditionEffective Java Second Edition
Effective Java Second Edition
 
I x scripting
I x scriptingI x scripting
I x scripting
 
Type system
Type systemType system
Type system
 
Java New Programming Features
Java New Programming FeaturesJava New Programming Features
Java New Programming Features
 
(6) collections algorithms
(6) collections algorithms(6) collections algorithms
(6) collections algorithms
 
Beginning linq
Beginning linqBeginning linq
Beginning linq
 
typescript.pptx
typescript.pptxtypescript.pptx
typescript.pptx
 
Notes(1).pptx
Notes(1).pptxNotes(1).pptx
Notes(1).pptx
 
Generics Collections
Generics CollectionsGenerics Collections
Generics Collections
 
(2) collections algorithms
(2) collections algorithms(2) collections algorithms
(2) collections algorithms
 
C#ppt
C#pptC#ppt
C#ppt
 
Csharp_mahesh
Csharp_maheshCsharp_mahesh
Csharp_mahesh
 
Synapseindia dot net development
Synapseindia dot net developmentSynapseindia dot net development
Synapseindia dot net development
 
Abstract Data Types (a) Explain briefly what is meant by the ter.pdf
Abstract Data Types (a) Explain briefly what is meant by the ter.pdfAbstract Data Types (a) Explain briefly what is meant by the ter.pdf
Abstract Data Types (a) Explain briefly what is meant by the ter.pdf
 

More from Nico Ludwig

Grundkurs fuer excel_part_v
Grundkurs fuer excel_part_vGrundkurs fuer excel_part_v
Grundkurs fuer excel_part_vNico Ludwig
 
Grundkurs fuer excel_part_iv
Grundkurs fuer excel_part_ivGrundkurs fuer excel_part_iv
Grundkurs fuer excel_part_ivNico Ludwig
 
Grundkurs fuer excel_part_iii
Grundkurs fuer excel_part_iiiGrundkurs fuer excel_part_iii
Grundkurs fuer excel_part_iiiNico Ludwig
 
Grundkurs fuer excel_part_ii
Grundkurs fuer excel_part_iiGrundkurs fuer excel_part_ii
Grundkurs fuer excel_part_iiNico Ludwig
 
Grundkurs fuer excel_part_i
Grundkurs fuer excel_part_iGrundkurs fuer excel_part_i
Grundkurs fuer excel_part_iNico Ludwig
 
(1) gui history_of_interactivity
(1) gui history_of_interactivity(1) gui history_of_interactivity
(1) gui history_of_interactivityNico Ludwig
 
(1) gui history_of_interactivity
(1) gui history_of_interactivity(1) gui history_of_interactivity
(1) gui history_of_interactivityNico Ludwig
 
New c sharp4_features_part_vi
New c sharp4_features_part_viNew c sharp4_features_part_vi
New c sharp4_features_part_viNico Ludwig
 
New c sharp4_features_part_v
New c sharp4_features_part_vNew c sharp4_features_part_v
New c sharp4_features_part_vNico Ludwig
 
New c sharp4_features_part_iv
New c sharp4_features_part_ivNew c sharp4_features_part_iv
New c sharp4_features_part_ivNico Ludwig
 
New c sharp4_features_part_iii
New c sharp4_features_part_iiiNew c sharp4_features_part_iii
New c sharp4_features_part_iiiNico Ludwig
 
New c sharp4_features_part_ii
New c sharp4_features_part_iiNew c sharp4_features_part_ii
New c sharp4_features_part_iiNico Ludwig
 
New c sharp4_features_part_i
New c sharp4_features_part_iNew c sharp4_features_part_i
New c sharp4_features_part_iNico Ludwig
 
New c sharp3_features_(linq)_part_v
New c sharp3_features_(linq)_part_vNew c sharp3_features_(linq)_part_v
New c sharp3_features_(linq)_part_vNico Ludwig
 
New c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_ivNew c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_ivNico Ludwig
 
New c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_ivNew c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_ivNico Ludwig
 
New c sharp3_features_(linq)_part_iii
New c sharp3_features_(linq)_part_iiiNew c sharp3_features_(linq)_part_iii
New c sharp3_features_(linq)_part_iiiNico Ludwig
 
New c sharp3_features_(linq)_part_ii
New c sharp3_features_(linq)_part_iiNew c sharp3_features_(linq)_part_ii
New c sharp3_features_(linq)_part_iiNico Ludwig
 

More from Nico Ludwig (20)

Grundkurs fuer excel_part_v
Grundkurs fuer excel_part_vGrundkurs fuer excel_part_v
Grundkurs fuer excel_part_v
 
Grundkurs fuer excel_part_iv
Grundkurs fuer excel_part_ivGrundkurs fuer excel_part_iv
Grundkurs fuer excel_part_iv
 
Grundkurs fuer excel_part_iii
Grundkurs fuer excel_part_iiiGrundkurs fuer excel_part_iii
Grundkurs fuer excel_part_iii
 
Grundkurs fuer excel_part_ii
Grundkurs fuer excel_part_iiGrundkurs fuer excel_part_ii
Grundkurs fuer excel_part_ii
 
Grundkurs fuer excel_part_i
Grundkurs fuer excel_part_iGrundkurs fuer excel_part_i
Grundkurs fuer excel_part_i
 
(2) gui drawing
(2) gui drawing(2) gui drawing
(2) gui drawing
 
(2) gui drawing
(2) gui drawing(2) gui drawing
(2) gui drawing
 
(1) gui history_of_interactivity
(1) gui history_of_interactivity(1) gui history_of_interactivity
(1) gui history_of_interactivity
 
(1) gui history_of_interactivity
(1) gui history_of_interactivity(1) gui history_of_interactivity
(1) gui history_of_interactivity
 
New c sharp4_features_part_vi
New c sharp4_features_part_viNew c sharp4_features_part_vi
New c sharp4_features_part_vi
 
New c sharp4_features_part_v
New c sharp4_features_part_vNew c sharp4_features_part_v
New c sharp4_features_part_v
 
New c sharp4_features_part_iv
New c sharp4_features_part_ivNew c sharp4_features_part_iv
New c sharp4_features_part_iv
 
New c sharp4_features_part_iii
New c sharp4_features_part_iiiNew c sharp4_features_part_iii
New c sharp4_features_part_iii
 
New c sharp4_features_part_ii
New c sharp4_features_part_iiNew c sharp4_features_part_ii
New c sharp4_features_part_ii
 
New c sharp4_features_part_i
New c sharp4_features_part_iNew c sharp4_features_part_i
New c sharp4_features_part_i
 
New c sharp3_features_(linq)_part_v
New c sharp3_features_(linq)_part_vNew c sharp3_features_(linq)_part_v
New c sharp3_features_(linq)_part_v
 
New c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_ivNew c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_iv
 
New c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_ivNew c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_iv
 
New c sharp3_features_(linq)_part_iii
New c sharp3_features_(linq)_part_iiiNew c sharp3_features_(linq)_part_iii
New c sharp3_features_(linq)_part_iii
 
New c sharp3_features_(linq)_part_ii
New c sharp3_features_(linq)_part_iiNew c sharp3_features_(linq)_part_ii
New c sharp3_features_(linq)_part_ii
 

Recently uploaded

AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...apidays
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Principled Technologies
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesBoston Institute of Analytics
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024The Digital Insurer
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 

Recently uploaded (20)

AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 

(4) collections algorithms

  • 2. 2 ● Collections – Part IV – Object-based vs. generic Collections ● Generics Types in Java – Sequential and associative Collections – Associative Collections ● Equivalence-based associative Collections: .Net's SortedDictionary ● Operations on .Net's IDictionarys ● Comparison and Implementation of .Net's Interfaces IComparable and IComparer TOC
  • 3. 3 ● Explicitly typed – i.e. typenames must be explicitly written at their declaration: ● Safely typed – i.e. unrelated types can't fool the compiler. – Cross casting and other pointer stuff is generally illegal. ● Statically typed – i.e. variables' types are determined at compile time: ● Sorry? But the same variable can hold different sub type objects at run time! – Indeed! We can define variables that may hold e.g. any derived type: – .Net differs the static (Object) and the dynamic type (Car) of an instance. – The idea of static/dynamic types is used for run time polymorphism in .Net. double sum = 5.2; // Type name "double" must be explicitly written for the variable sum. int count = 42; // count is of type int, we can only perform int operations on it! Object o = new Car(); // Type Car is derived from type Object. The Type System in .Net 1 (presented in C#1) – Part I
  • 4. 4 ● Esp. object-based collections rely on the cosmic hierarchy of .Net's type system: everything is an Object: – .Net 1 collections: Hold items of static type Object, their dynamic types can vary. ● In fact collections must be able to hold any type in order to be versatile. – .Net 1 "resorted" to run time polymorphism (i.e. Liskov Substitution Principle (LSP)) to get this versatility. – So in a .Net 1 collection, objects of any dynamic type can be stored. ● Object-based collections work great, as long as... – we'll only store objects of dynamic types that dependent code awaits, – we'll only cast down to dynamic types that dependent code put in, – we'll never put mixed unrelated dynamic types into the same collection, – well as we don't fall into a type problem during run time. ArrayList lines = new ArrayList(File.ReadAllLines("/Library/Logs/Software Update.log")); // File.ReadAllLines() was introduced with .Net 2! object item1 = lines[0]; object item2 = lines[1]; // We have to use cast contact lenses to get the dynamic types out of the objects: string text1 = (string)item1; // Access string's interface: int result = text1.IndexOf('g'); // We can also cast directly from the index notation: string text2 = (string)lines[1]; The Type System in .Net 1 (presented in C#1) – Part II
  • 5. 5 ● The problem or lack in the type system using LSP can be presented with the just created collection lines: ● The problem is that we as programmers have to know about the contained dynamic types (strings and not Cars in lines). – Whenever Object is used in an interface (the return value of lines' indexer), some convention must be around. – This convention describes the dynamic type, we're really dealing with (strings and not Cars). – The contributed programers have just to obey the convention... ;-) ● We as programmers have to cast down (or unbox) to the type we await. – The cast is needed to access the interface of a static type (e.g. car.StartEngine()). – These casts indicate that the programer knows more than the compiler! – The compiler wears "cast contact lenses"; it can't type check, it trusts the programmer! – These casts are type checked at run time, so they are consuming run time! – Type errors (an item of lines was casted to Car instead of string) will happen at run time, not at compile time. object item1 = lines[0]; // But, these are not the awaited types, we can't deal with Cars, we await strings! // This cast will fail! An InvalidCastException will be thrown! Car car = (Car)item1; car.StartEngine(); public class Car { public void StartEngine() { /* pass */ } } The Type System in .Net 1 (presented in C#1) – Part III
  • 6. 6 ● Object-based collections have an interesting feature: we can be heterogeneous collections: – In a heterogeneous collection every item can have any different dynamic type: ● It works, but heterogeneous collections are tricky: developers need to know, on which indexes objects of certain types reside. ● Heterogenous collection should be avoided! Strive to using homogenous collections or other solutions! ArrayList objects = new ArrayList(); // Since each item is of type object, we can add any object to an ArrayList: objects.Add("aString"); // String objects.Add(42); // int objects.Add(new object()); // object objects.Add(new [] {1, 2, 3, 4}); // int[] foreach(object item in objects) { Console.WriteLine(item); } // This statement will fail, we can't deal with string, on index 1 an int was stored! // An InvalidCastException will be thrown! string result = (string)objects[1]; Homogeneous and heterogeneous Collections
  • 7. 7 ● What could we do close the lack in the .Net 1 type system to stay typesafe? ● We could use strictly typed arrays as collections if possible, they're not object-based and therefore typesafe: – However, arrays can not be used, when the collection in question needs to be modified (enlarged or downsized) after creation. ● We could create own, typesafe not object-based collections as UDTs (e.g. a special string-list for the discussed example). – In .Net we could resort to so called specialized collections in the namespace System.Collections.Specialized, e.g. StringCollection. ● But in the world of collections, there is a much better way to work in a typesafe manner: generic collections! // Create an array that hold strings: string[] lines = File.ReadAllLines("/Library/Logs/Software Update.log")); // With arrays we don't need casts, instead we can directly access lines' items as string objects: string text1 = lines[0]; // Access string's interface: int result = text1.IndexOf('g'); // Create a specialized StringCollection: StringCollection lines = new StringCollection(); lines.AddRange(File.ReadAllLines("/Library/Logs/Software Update.log")); // With the specialized StringCollection we don't need casts, instead we can directly access lines' items as string objects: string text1 = lines[0]; // Access string's interface: int result = text1.IndexOf('g'); The Type System in .Net 1 – Some Remedy
  • 8. 8 ● Let's improve our problematic code with the generic collection List<T>: ● .Net 2 introduced generic types to get rid of the presented type problems. – Generic types are types that leave a part of their type information open. – Generics are an outstanding feature in .Net 2. ● Generics (here List<T>) leave type information open? How should this help me out? – The open type information is accessible by type parameters (here T). – As programmers we can fill the type parameters by concrete type arguments (here string). – By setting type arguments of a generic type we create another type, the constructed type (List<string> in this case). ● The full name of the constructed type is List<string>! – => Net effect: The type argument (string) will be of static type, so the formerly open type information can be checked by the compiler. – In the end typesafety means that types are checked by the compiler at compile time and no longer at run time. // Create a generic List that holds strings: List<string> lines = new List<string>(File.ReadAllLines("/Library/Logs/Software Update.log")); // This time we don't need casts, instead we can directly access lines' items as string objects: string text1 = lines[0]; // Access string's interface: int result = text1.IndexOf('g'); // The generic type List<T>: public class List<T> { // (members hidden) public void Add(T item) { /* pass */ } } // This time we'll get a compile time error: Car car1 = lines[1]; // The type argument in lines was string, not Car! // Cannot convert string to Car. car1.StartEngine(); Generics to the Rescue
  • 9. 9 ● .Net's generic collections live in the namespace System.Collections.Generic. ● The generic counterpart of the collection ArrayList is List<T>, T is the type parameter. – List<T>'s interface is set to the open type T in parameter- and return-types of methods. – The type parameter T acts as a placeholder for the actual type argument. ● When a type is constructed, T is replaced by a type argument (the result is the constructed type). – List<string>'s interface is set to the static type string in parameter- and return- types of methods. ● The idea of generics is to use types (i.e. not values) as arguments! – The typesafty we got is that generics move type run time errors to compile time errors. // The generic type List<T>: public class List<T> { // (details hidden) public void Add(T item) { /* pass */ } public List<T> GetRange(int index, int count) { /* pass */ } } // The constructed type List<string> has following interface: public class List<string> { // (details hidden) public void Add(string item) { /* pass */ } public List<string> GetRange(int index, int count) { /* pass */ } } // Create a generic List that holds strings: List<string> lines; List T The UML represents generic types as parameterized classes. Generics – Overview List<T -> string> «bind» <T -> string> List<string> implicit binding against a type argument explicit binding against a type argument
  • 10. 10 ● It is also possible to define generic types, whose type argument is another generic type. – E.g. we can define a list of lists, i.e. a collection of collections, which is effectively a two-dimensional array or matrix. – Such collections are better than multidimensional arrays in some aspects: ● They offer the same concept to express rectangular as well as jagged arrays. ● "Real" collections are very flexible, as elements can be added and removed (or: the matrix' dimensions can be enlarged and shrank). ● The .Net framework as well as Java do also support generic types having two or more type parameters: – E.g. with the type SortedDictionary<TKey, Tvalue> (this type will be discussed later): ● To understand collections in Java, C++ and .Net it is required to understand also advanced generics. // Creating a SortedDictionary object: SortedDictionary<string, int> aDictionary = new SortedDictionary<string, int>(); aDictionary.Add("fortytwo", 42); // The generic type SortedDictionary<TKey, TValue>: public class SortedDictionary<TKey, TValue> { // (members hidden) /* pass */ } // A jagged array in C# as matrix: int[][] matrix = new int[3][]; matrix[0] = new[] {1, 2, 3, 4}; matrix[1] = new[] {6, 7}; matrix[2] = new[] {8, 9, 0}; Console.WriteLine("Item: {0}", matrix[1][0]); // >Item: 6 // A list of lists of int as matrix: List<List<int>> matrix = new List<List<int>>(); matrix.Add(new List<int>{1, 2, 3, 4}); matrix.Add(new List<int>{6, 7}); matrix.Add(new List<int>{8, 9, 0}); Console.WriteLine("Item: {0}", matrix[1][0]); // >Item: 6 Slightly advanced Generics
  • 11. 11 ● Hence, we'll use generic types whenever appropriate. We'll define following substitutes for already introduced collections: – ICollection → ICollection<T> – IList → IList<T> – ArrayList → List<T> – IEnumerable → IEnumerable<T> – IEnumerator → IEnumerator<T> – .Net's framework design guidelines suggest using only generic collection types in public interfaces. ● From object-based to generic collections: IList names = new ArrayList(); names.Add("James"); names.Add("Miranda"); // Get the values back (object-based collection: static type Object): object name1 = names[0]; // "James" object name2 = names[1]; // "Miranda" string name1AsString = (string)name1; // Cast the string out of the object. string name2As = (string)names[1]; // Cast directly from the index notation. names[1] = "Meredith"; Console.WriteLine(names[1]); // >Meredith IList<string> names = new List<string>(); names.Add("James"); names.Add("Miranda"); // Get the values back (generic string-collection: static type string): string name1 = names[0]; // "James" string name2 = names[1]; // "Miranda" names[1] = "Meredith"; Console.WriteLine(names[1]); // >Meredith The better Type System – from object-based to generic Collections
  • 12. 12 ● C++ templates are, at least principally, C++' equivalent to .Net's and Java's generics. – C++ provides the template std::vector<T> (<vector>), which is functionally equivalent to .Net's List<T>: – Before C++ had templates, void*-based collections have been used, incl. cast contact lenses. - This is still true for C. ● void*-based collections are the functional equivalent to object-based collections! ● Objective-C and many scripting languages use so called dynamic typing instead of generic or object-based structures. – (We're not going to discuss these concepts in this course.) // names is a vector containing string-elements. std::vector<std::string> names; names.push_back("James"); names.push_back("Miranda"); // Get the values back (template string-container: static type std::string): std::string name1 = names[0]; // "James" std::string name2 = names[1]; // "Miranda" names[1] = "Meredith"; std::cout<<names[1]<<std::endl; // >Meredith // in h-file <vector> template <typename T> class vector { // (details hidden) public: void push_back(const T& newItem); }; The Collection Type System of the C++ STL
  • 13. 13 ● The story about generic collections in Java is somewhat advanced, but Java programmers should know these facts. – A good way to understand Java's generics (and the problems that come with it) is to compare them to, e.g., .Net's generics. ● Here we have basically the same generic class in Java and C#: – The definition of instances of these classes has almost the same syntax in Java and C#: ● In Java we can only use reference types as type arguments for generic types. E.g. we can not create MyList<int> or MyList<double>. – As we know the idea behind generics is to have typesafty. So the last statements won't compile respectively: The Collection Type System on the Java Platform – Part I // Java public class MyList<T> { public List<T> items = new ArrayList<T>(5); } // Java stringList.items.add("Frank"); // OK for the compiler! A string literal can be set, because items is a List<String>. stringList.items.add(42); // Invalid for the compiler! Generics are typesafe! An int literal can't be set, because items is not a List<Integer>. MyList<String> stringList = new MyList<String>(); MyList<Integer> intList = new MyList<Integer>(); MyList<string> stringList = new MyList<string>(); MyList<int> intList = new MyList<int>(); // C# public class MyList<T> { public IList<T> items = new List<T>(5); } // C# stringList.items.Add("Frank"); // OK for the compiler! See explanation for Java above. stringList.items.Add(42); // Invalid for the compiler! See explanation for Java above.
  • 14. 14 ● The difference between Java and .Net is that different things are generated at compile time. – A compiler creating .Net IL code will produce a so called constructed type for each "filled out" generic type in the code: – A compiler creating Java bytecode will just erase the type argument and will fall back to an object-based type: ● This compilation step is called type erasure. The resulting type (w/o generic type parameters) is called the raw type of the generic type. ● Often this isn't a problem in Java, because compile time typesafety is fine, but it hurts the run time typesafety! ● Ouch! But Java provides a means to reestablish run time typesafety: run time type checked collection wrappers. The Collection Type System on the Java Platform – Part II stringList.items.add("Frank"); // Ok as before! ((MyList)stringList).items.add(42); // Huh? Casting (cast contact lenses) to the raw type and adding an int: ok for compiler and at run time! String itemAt1 = stringList.items.get(1); // Bang! Getting the int at the index one via the generic type: ok for the compiler but crashes at run time! // java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String type construction of a .Net IL compiler // Java MyList<String> stringList = new MyList<String>(); MyList<Integer> intList = new MyList<Integer>(); public class MyList { // Raw type public List items = new ArrayList(5); } type erasure of a Java bytecode compiler // C# MyList<string> stringList = new MyList<string>(); MyList<int> intList = new MyList<int>(); public class MyList<string> { // Constructed type public IList<string> items = new List<string>(5); } public class MyList<int> { // Constructed type public IList<int> items = new List<int>(5); }
  • 15. 15 ● Java provides the class Collections with some static methods (simple factories) to create run time type checked collections. – A present collection needs to be passed to Collections.checked...() and a new collection wrapping the passed one will be returned. – Let's wrap MyList's encapsulated List to be a checked List with Collections.checkedList(): ● More simple factories can be found in the class Collections as static methods (checkedSet(), checkedMap() etc.). – The return type of all of these simple factories are just interface types, the type checked implementations are always hidden. – So the UML diagram of the relations between the contributing types looks like so: ● Run time type checked wrappers were added to the JDK in order have compatibility w/ non-generic collections, retaining compile time typesafty of generics and having run time typesafety. – There is an initiative in the Java community to introduce generic types with constructed types into Java: reified generics. – Mind that run time type checking is costly! The Collection Type System on the Java Platform – Part III stringList.items = Collections.checkedList(stringList.items, String.class); // Wrap items, so that it can only deal with strings at compile time. stringList.items.add("Frank"); // Ok as before! It was already checked by the compiler. ((MyList)stringList).items.add(42); // Bang! An int can't be added to a list that is only allowed to contain Strings! String itemAt1 = stringList.items.get(1); // Will not be reached at all! <<interface>> List HiddenCheckedListImplementation exposes implements Collections + checkedList(list : List<T>, type : Class<T>) : List<T> instantiates T
  • 16. 16 ● Up to now, we discussed relatively simple indexed and sequential collections. ● Besides indexed and sequential collections there also exist so called associative collections. ● In opposite to indexed and sequential collections, associative collections inspect the stored objects. – E.g. the indexed collection ArrayList just stores references to objects, but it does never, e.g., call methods on these objects. ● For indexed and sequential collections the contained items are said to be transparent. – Associative collections have to inspect stored objects for equivalence or equality in order to provide very mighty features. ● Let's start by analyzing a problem, which can be solved with associative collections. Indexed, sequential and associative Collections
  • 17. 17 ● Let's assume that we have to handle color names and figure out the belonging to HTML color codes: ● Of course the task can be solved this way, but the solution is based on a possibly fragile assumption: – The two separate arrays need to hold belonging to values at the same indexes! – Basically we've to go through all items sequentially and compare (Array.IndexOf()). – We say the association is index-based. ● The presented algorithm is a so called lookup-algorithm (lookup). – Lookups are used very often in programming. – A problem of lookups is that separate collections (colorNames and htmlColorCode) need to be evaluated (like tables in relational databases). – Modern collection frameworks provide dedicated collections to cover lookups in a comfortable manner: associative collections. // C# // Here we have two arrays that hold color names and HTML color codes: string[] colorNames = {"Blue", "Red", "Green"} ; int[] htmlColorCodes = {0x0000FF, 0xFF0000, 0x00FF00}; // With the information given, the task to pick an HTML color code from a color name is trivial: Because the // index of the color name matches the index of the color HTML code, we can formulate a simple algorithm: int indexOfRed = Array.IndexOf(colorNames, "Red"); int colorCodeOfRed = htmlColorCodes[indexOfRed]; Console.WriteLine("Color code for Red: {0:X6}", colorCodeOfRed); // >Color code for Red: FF0000 colorNames0x0000FF 0xFF0000 0x00FF00 "Blue" "Red" "Green" htmlColorCodes 210 matching indexes Example – Color Names to HTML Color Codes – Part I
  • 18. 18 colorNamesToColorCodes ● Associative collections abstract the usage of multiple collections to solve the just presented lookup in an intuitive manner: – Here .Net's associative collection SortedDictionary<string, int> is shown (it implements IDictionary<string, int>): – The association of both, color names and color codes, is available via the single collection colorNamesToHtmlColorCodes. ● We have to rethink our termination: associative collections associate a key (color name) to a value (color code). – The association is key-based and no longer index-based. – The internal "organization" is key-value-pair-based. – In a sense an array is nothing but an associative collection that associates a value with an index (mind the []-syntax). – In fact real problems often involve associating values with other values, e.g.: White pages, thesaurus, document index. ● The .Net collection KeyedCollection<K, T> allows the lookup of data stored in the value (i.e. there are no key-value-pairs). // Associating color names with HTML color codes using a SortedDictionary: IDictionary<string, int> colorNamesToColorCodes = new SortedDictionary<string, int>(); colorNamesToColorCodes.Add("Blue", 0x0000FF); colorNamesToColorCodes.Add("Red", 0xFF0000); colorNamesToColorCodes.Add("Green", 0x00FF00); int colorCodeOfRed = colorNamesToColorCodes["Red"]; Console.WriteLine("Color code for Red: {0:X6}", colorCodeOfRed); // >Color code for Red: FF0000 0x0000FF 0xFF0000 0x00FF00 "Blue" "Red" "Green" Key-value-pair {"Green", 0x00FF00} Example – Color Names to HTML Color Codes – Part II
  • 19. 19 ● In many scripting languages associative collections have special syntactical support. – The names "hash", "hashmap" or "associative array" are common in scripting languages. – In JavaScript every object is a collection of property-value-pairs per se. An array is also an associative collection: ● In other platforms associative collections are often called Maps (Java) or Dictionaries (Cocoa, .Net). – Esp. the term "Map" is taken from the phrase "to map something", which means "to associate something". – The term "hash" still needs to be clarified in this context: we have to understand how associative collections work. ● We'll start discussing equivalence-based associative collections and then equality-based associative collections using hashing. # E.g. in Ruby associative collections are supported as "hashes" with integrated syntactical support. # Just initialize a variable with a list of key => value pairs: colorNamesToColorCodes = {"Blue" => 0x0000FF, "Red" => 0xFF0000, "Green" => 0x00FF00} # The items can be accessed with the []-operator: printf("Color code for Red: %06X", colorNamesToColorCodes["Red"]) # >Color code for Red: FF0000 // JavaScript // Create associative collection as object with properties: var colorNamesToColorCodes = new Object(); colorNamesToColorCodes.Blue = 0x0000FF; colorNamesToColorCodes.Red = 0xFF0000; colorNamesToColorCodes.Green = 0x00FF00; console.log("Color code for Red: " +colorNamesToColorCodes.Red.toString(16)); // >Color code for Red: FF0000 // JavaScript // Create associative collection as associative array: var colorNamesToColorCodes = new Object(); colorNamesToColorCodes["Blue"] = 0x0000FF; colorNamesToColorCodes["Red"]= 0xFF0000; colorNamesToColorCodes["Green"]= 0x00FF00; console.log("Color code for Red: " +colorNamesToColorCodes["Red"].toString(16)); // >Color code for Red: FF0000 Associative Collections in other Languages
  • 20. 20 ● New about associative collections is that associative collections inspect the items they hold. – I.e. associative collections operate on contained items: they call methods on the keys of the contained key-value-pairs. – Associative collections need to compare the keys they hold. – In opposite to other collections, items are got and set by analyzing their relationships. ● Associative collections are very powerful and allow writing elegant/readable algorithms to solve complicated problems. – Associative collections could be implemented with two arrays as shown before, but this would be inefficient for common cases. – A clever internal organization of associative collections is required to allow efficient access and modification of contained items. ● There are two general ways to organize items (i.e. their keys) in an associative collection: – (1) By equivalence. I.e. by their relative order/order-relationship, such as less than and greater than. – (2) By equality. I.e. by hash-codes and the result of the equality check (methods hashCode()/equals() (Java) or GetHashCode()/Equals() (.Net)). ● In this and the next lecture we're going to discuss associative collections that organize their keys by equivalence. – This is the case for SortedDictionary, so we'll discuss .Net's SortedDictionary. Organization of Items in associative Collections
  • 21. 21 ● Create the empty SortedDictionary<K, V> colorNamesToColorCodes: ● Then we can add three key-value-pairs like so: ● Get the value of a key, i.e. make a lookup with the indexer ([]-operator): ● Check, whether an entry with a certain key is already existing with the method ContainsKey(): ● Iteration: The internal organization is key-value-pair-based, so IDictionary's iterator produces an iterator of key-value pairs. C# – collection initializers for dictionaries // Apply a collection initializer on a SortedDictionary: IDictionary<string, int> colorNamesToColorCodes2 = new SortedDictionary<string, int> { {"Blue", 0x0000FF}, {"Red", 0xFF0000}, {"Green", 0x00FF00} }; IDictionary<string, int> colorNamesToColorCodes = new SortedDictionary<string, int>(); colorNamesToColorCodes.Add("Blue", 0x0000FF); colorNamesToColorCodes.Add("Red", 0xFF0000); colorNamesToColorCodes.Add("Green", 0x00FF00); int valueForBlue = colorNamesToColorCodes2["Blue"]; // >0x0000FF Operations on IDictionarys – Part I // IDictionary<string, int> implements IEnumerable<KeyValuePair<string, int>>. // Iteration yields KeyValuePair<string, int>-items: foreach (KeyValuePair<string, int> item in colorNamesToColorCodes) { Console.WriteLine(item); } bool blueAlreadyPresent = colorNamesToColorCodes2.ContainsKey("Blue"); // >true
  • 22. 22 ● Trying to query the value for a key that doesn't exist will throw a KeyNotFoundException: – To avoid these "surprises" check the key for existence (with ContainsKey()), before it is looked up. ● Adding a pair for an already existing key will throw an ArgumentException. – .Net dictionaries don't allow having a key with multiple values. (However, the C++' STL-container std::multimap can handle this.) ● The indexer allows adding new entries as well as replacing values of existing key-value-pairs and reading values: ● We can get the current count of elements stored in the dictionary (Count is required by implementing ICollection<T>): colorNamesToColorCodes.Add("Blue", 17); // Throws ArgumentException: a key-value-pair with the same key already exists in the dictionary. colorNamesToColorCodes["Blue"] = 17; // OK! Replaces "Blue"'s value 0x0000FF with 17. colorNamesToColorCodes["Yellow"] = 0xFFFF00; // Adds the new key-value-pair {"Yellow", 0xFFFF00}. if (colorNamesToColorCodes.ContainsKey("Yellow")) { // Checking the existence of the key "Yellow". // Use the indexer to retrieve "Yellow"'s value: Console.WriteLine("Color code for Yellow: {0:X6}", colorNamesToColorCodes["Yellow"]); // >Color code for Yellow: FFFF00 } Console.WriteLine(colorNamesToColorCodes.Count); // >4 Operations on IDictionarys – Part II int valueForOrange = colorNamesToColorCodes2["Orange"]; // Throws KeyNotFoundException: a key-value-pair with that key doesn't exists in the dictionary.
  • 23. 23 ● Now its time to understand how SortedDictionarys work basically, we'll discuss it in depth in the next lecture. – We have to clarify, how SortedDictionary knows if a key is already present or not! - It needs to compare keys somehow! ● The question is: "How does SortedDictionary know if two keys are equal?" – A part of the answer is that SortedDictionary doesn't know, if two items are equal, but it knows if two items are equivalent! – SortedDictionary's comparison is based on the order-relationship among items. This is called equivalence comparison. ● The order-relationship can be expressed by evaluating two values one being less than, greater than or equal the other. – If of two values one is neither less than nor greater than the other the values are said to be equivalent (Not equal!). – .Net provides a way for types to declare equivalence comparability: implementing the interface IComparable/IComparable<T>. – (The C++ STL requires types to override operator< to implement equivalence comparability.) ● Now we are going to understand how IComparable/IComparable<T> has to be implemented for own UDTs. SortedDictionary and Equivalence Comparison
  • 24. 24 UDTs as Keys of associative Collections – Part I ● Up to now we've only used objects of builtin types for the keys of associative collections (e.g. string). – Now we are going to explore how to use keys of our own types. Let's do this with the UDT Car: – Obviously it doesn't work this way! - What did we miss? ● The problem is that nobody (esp. SortedDictionary) knows, how to compare Cars! – One way to implement this: Car could itself know, how it can be compared – we've to implement IComparable<Car> in Car: – IComparable<T>.CompareTo() should return a value less than 0, if this < other, a value greater than 0, if this > other and otherwise 0. ● For Car we'll delegate the implementation of IComparable<Car>.CompareTo() to Car's property Name, Name is of type string (string implements IComparable<string>). – With this implementation of Car SortedDictionary<TKey, TValue> works as expected: public class Car { public string Name {get; set;} } IDictionary<Car, string> carToManufacturer = new SortedDictionary<Car, string>(); // Adding the first item won't require to compare items: carToManufacturer[new Car{ Name = "Focus" }] = "Ford"; // Will throw ArgumentException: Object doesn't implement IComparable! carToManufacturer[new Car{ Name = "Auris" }] = "Toyota"; IDictionary<Car, string> carToManufacturer = new SortedDictionary<Car, string>(); carToManufacturer[new Car{ Name = "Focus" }] = "Ford"; // OK! carToManufacturer[new Car{ Name = "Auris" }] = "Toyota"; public class Car : IComparable<Car> { // (members hidden) public int CompareTo(Car other) { // Very simple implementation that compares the Cars' Name fields: return this.Name.CompareTo(other.Name); } }
  • 25. 25 UDTs as Keys of associative Collections – Part II ● But there are cases, in which implementing IComparable<T> is no option to make types usable as keys: – (1) if we can not modify the type in question, e.g. if it is a type of a 3rd party library, – (2) if the type in question does already implement IComparable<T>, but the implemented comparison doesn't meet our needs, – (3) if the type doesn't implement IComparable<T> at all. ● Let's assume that we want to use Cars as keys by case insensitive comparison of their Name property. – We could change the implementation of Car.CompareTo(), but this would hurt the Open-Close Principle (OCP). – Effectively we have the case (2). The present implementation of IComparable<Car> doesn't meet our needs. ● To cover these cases there is another way to implement comparison: implement comparison in a different type (not in Car). – I.e. we can implement a dedicated type that has only one responsibility: comparing Cars. Such a type is called comparator. – The .Net framework provides a special interface to support such special comparison types: IComparer/IComparer<T>. – Now it's time to implement a comparer to compare the case insensitive Name of Cars.
  • 26. 26 UDTs as Keys of associative Collections – Part III ● The type SortedDictionary<TKey, TValue> accepts an object of type IComparer<TKey> in one of its ctors: – As can be seen the passed comparer refers to the type TKey. ● The comparer to specify in the ctor determines, how Cars are getting compared. The comparer looks like this: ● Here we'll finally pass an instance of the created CaseInsensitveCarComparer to SortedDictionary's ctor: public class CaseInsensitiveCarComparer : IComparer<Car> { public int Compare(Car lhs, Car rhs) { // Very simple implementation that compares the Name // fields of two Cars ignoring the case: return string.Compare(lhs.Name, rhs.Name, true); } } // The generic type SortedDictionary<TKey, TValue>: public class SortedDictionary<TKey, TValue> { // (details hidden) public SortedDictionary(IComparer<TKey> comparer); } // Create a dictionary and specify the special comparer in the ctor: IDictionary<Car, string> carToManufacturer = new SortedDictionary<Car, string>(new CaseInsensitiveCarComparer()); carToManufacturer[new Car{ Name = "Cortina" }] = "Ford"; // This won't add another "cortina", because the specified comparer evaluates "Cortina" and "cortina" as being equivalent. carToManufacturer[new Car{ Name = "cortina" }] = "Lotus"; // Will set "Cortina"'s value to "Lotus". Console.WriteLine("Count of items: {0}", carToManufacturer.Count); // >Count of items: 1
  • 27. 27 Controlling String-Key Comparison ● If we use strings as keys (i.e. not a UDT like Car), we can use predefined comparers to compare case insensitively. – The .Net framework provides a set of predefined StringComparer objects in the type StringComparer. – Let's rewrite the color code example for case insensitive color names: – We can do the same with Java's TreeMap managing string-keys case-insensitively using a special Comparator: – If we like to exploit the sorting of the Map and want the keys to be sorted in descending order, just reverse the Comparator: // Create a dictionary and specify the case insensitive string comparer in the ctor: IDictionary<string, int> colorNamesToColorCodes = new SortedDictionary<string, int>(StringComparer.OrdinalIgnoreCase); colorNamesToColorCodes.Add("Green", 0x00FF00); // Because of the case insensitive comparison "Green" and "green" are seen as equivalent key objects: int colorCodeOfGreen = colorNamesToColorCodes["green"]; Console.WriteLine("Color code for Green: {0:X6}", colorCodeOfGreen); // >Color code for Green: 00FF00 // Create a map and specify the case insensitive string comparator in the ctor: Map<String, Integer> colorNamesToColorCodes = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); colorNamesToColorCodes.put("Green", 0x00FF00); // Because of the case insensitive comparison "Green" and "green" are seen as equivalent key objects: int colorCodeOfGreen = colorNamesToColorCodes.get("green"); System.out.printf("Color code for Green: %06X%n", colorCodeOfGreen); // >Color code for Green: 00FF00 // Create a map and specify the case insensitive string comparator in the ctor, the sorting should be descending: Map<String, Integer> colorNamesToColorCodesDescending = new TreeMap<>(Collections.reverseOrder(String.CASE_INSENSITIVE_ORDER));

Editor's Notes

  1. Mind how the term key (primary/foreign key) is also applied in the design of databases. Indeed KeyedCollection is a very useful collection. However, it is not a classical associative collection, because it uses linear search (it is backed by a List and calls Contains() on that List potentially for each item). The abstract class KeyedCollection needs to be specialized (overriding GetKeyForItem(), i.e. we have the template method design pattern here) to get the key from the managed item/value.
  2. It should be mentioned that some methods of list-types already needed to inspect the contained items to function, e.g. Contains(), Remove(), IndexOf(). These methods use equality to inspect/compare values.
  3. Because colorNamesToColorCodes is virtually a SortedDictionary, the iteration will yield the items in the order sorted by their keys.
  4. The associative collection does really look into the items: just set a breakpoint into the Car. CompareTo() method!
  5. If a type does not implement IComparable&amp;lt;T&amp;gt;, and we try to add at least two instances of that type used as key into a SortedDictionary, an ArgumentException will be thrown.
  6. Creating a reversed Comparer by passing an existing Comparer to Collections.reverseOrder() is an example of the decorator pattern. A present Comparer is decorated with extra functionality and the new object has the same interface than the one being decorated.