Windows Programming Using C# Arrays, Collections Contents Arrays Collections Generics Strings 2 Arrays Arrays are similar to Java int[] intArray; Creates a reference to an array intArray = new int[5]; Creates an array object and assigns it Array objects are reference types created on the heap The integers in the array are value types Array indexing is zero based 3 System.Array All arrays are derived from this class Properties – number of elements in all dimensions Rank – number of dimensions Length Methods BinarySearch – performs a binary search for a member 4 System.Array – sets a range of elements to 0 or null Clone – creates a shallow copy Copy – copies elements from one array to another getLength – returns the length of a single dimension IndexOf – returns the first occurrence of a value Sort – sorts the array Clear 5 Arrays of Objects When you create an array of objects, it is simply an array of references to objects, not the actual objects These references are initialized to null You must then create objects and assign to each member of the array 6 The foreach Statement This iterates through all elements of an array or collection foreach (type ident in expression) statement int[] ar = new int[5] {1,2,3,4,5}; foreach(int i in ar) { Console.WriteLine(i); } 7 Rectangular Arrays C# supports rectangular and jagged arrays Arrays can be of 1 or more dimensions To declare a rectangular array int[,] int2d = new int[2,3]; for (int i = 0; I < 2; i++) { for(int j = 0; j < 3; j++) { int2d[i,j] = i+j; } } 8 Jagged Arrays These are really arrays of arrays Each member must be created as a separate array Note the difference in subscripting int jag[][] = new int[2][]; jag[0] = new int[5]; jag[1] = new int[10]; jag[0][1] = 15; 9 Indexers Indexers allow any class to be indexed like an array Indexers are declared in a way similar to properties They always use the keyword this The index can be an integer or even a string * see IndexedArray 10 Indexers Create a simple array which can be indexed By an integer By a string using “first”, “middle” or “last” class IndexedArray int[] data; { public IndexedArray(int sz) { data = new int[sz]; } … 11 Indexers An indexer with integer indices public int this[int index] { get { return data[index]; } set { data[index] = value; } } 12 Indexers An indexer with string indices public int this[string index] { get { int idx = 0; switch (index) { case "middle": idx = data.Length / 2; break; case "first": idx = 0; break; case "last": idx = data.Length - 1; break; } return data[idx]; } } 13 Contents Arrays Collections Generics Strings 14 Collections Collections are generic data structures for containing objects or primitives These are often in the form of common data structures like lists, and dictionaries Many of the collections have interfaces representing their functionality 15 The IEnumerable Interface This states that the class supports an enumerator or iterator which steps through the elements one-by-one Classes which implement this interface can be used with the foreach statement public interface IEnumerable { IEnumerator GetEnumerator(); } 16 The IEnumerator Interface This is the interface the enumerator must implement It is usually implemented as a private class within the class being enumerated public interface IEnumerator { bool MoveNext(); bool Reset(); object Current { get; } } 17 IndexedArrayEnumerator private class IndexedArrayEnumerator: IEnumerator int idx; IndexedArray theArray; public IndexedArrayEnumerator(IndexedArray ar) theArray = ar; idx = -1; } { { public bool MoveNext() { idx++; if(idx >= theArray.data.Length) return false; else return true; } public void Reset() idx = -1; } { public object Current { get{ return theArray[idx]; } } } 18 Getting an Enumerator public IEnumerator GetEnumerator() { return new IndexedArrayEnumerator(this); } This creates and returns an enumerator Using a separate enumerator class allows several enumerators to operate at the same time 19 The ICollection Interface Defines properties and methods for all collections Implements: IEnumerable Count the number of elements in the collection CopyTo(Array ar, int idx) Copies all elements to an array starting at the index 20 ArrayLists The problem with arrays is their fixed size ArrayLists fix this by resizing the array when the addition of new members exceeds the capacity The class has an extensive set of methods 21 ArrayList Methods Method/Property Description Capacity The number of elements the list can hold Item() Indexer Add() Add an object to the ArrayList AddRange() Add the elements of a collection to the end of the array BinarySearch() Binary search Clear() Removes all elements from the ArrayList Clone() Creates a shallow copy Contains() Determines if a value is in the ArrayList CopyTo() Copies to a 1-D array 22 ArrayList Methods Method/Property Description GetEnumerator() Returns an enumerator GetRange() Copies a range to a new ArrayList IndexOf() Returns the index of the first occurrence of a value InsertRange() Inserts elements from a collection Remove() Removes the first occurrence of an element RemoveAt() Removes the element as a specific location Sort() Sorts the ArrayList ToArray() Copies the elements to a new array TrimToSize() Sets capacity to current size 23 Sorting Sorting primitives is easy since comparing one to another is well-defined Sorting user-defined types is more difficult since you do not know how to compare one to another There are two solutions IComparable IComparer 24 The IComparable Interface This require one method CompareTo which returns -1 if the first value is less than the second 0 if the values are equal 1 if the first value is greater than the second This is a member of the class and compares this to an instance passed as a parameter public interface IComparable { int CompareTo(object obj) } 25 The IComparer Interface This is similar to IComparable but is designed to be implemented in a class outside the class whose instances are being compared Compare() works just like CompareTo() public interface IComparer { int Compare(object o1, object o2); } 26 Sorting an ArrayList To use CompareTo() of IComparable ArrayList.Sort() To use a custom comparer object ArrayList.Sort(IComparer cmp) To sort a range ArrayList.Sort(int start, int len, IComparer cmp) 27 Implementing IComparer To sort people based on age class PersonComparer: IComparer { public int Compare(object o1, object o2) { PersonBase p1 = (PersonBase)o1; PersonBase p2 = (PersonBase)o2; return p1.Age.CompareTo(p2.Age); } } 28 ICloneable Interface This guarantees that a class can be cloned The Clone method can be implemented to make a shallow or deep clone public interface ICloneable { object Clone(); } 29 Queue Class • Implements: ICollection, IComparable, ICloneable Method Description Enqueue(object) Adds an object to the queue object Dequeue() Takes an object off the queue and returns it. Throws InvalidOperationException if empty. object Peek() Returns object at head of queue without removing it. object[] ToArray() Returns contents as an array. 30 Stack Class • Implements: ICollection, IComparable, ICloneable Method Description Push(object) Adds an object to the stack object Pop() Takes an object off the stack and returns it. Throws InvalidOperationException if empty. object Peek() Returns object at top of stack without removing it. object[] ToArray() Returns contents as an array. 31 IDictionary Interface A dictionary is an associative array It associates a key with a value and allows a value to be retrieved by providing the key Implements: ICollection, IEnumerable 32 IDictionary Interface Method/Property Description Add(object key, object value) Adds a key and value to the collection Remove(object key) Removes the key and value pair bool Contains(object key) True if the dictionary contains the key IDictionaryEnumerator GetEnumerator() Returns an enumerator object this[object key] Gets or sets item with specified key. If the key does not exist, it is created. ICollection Values Returns the values as a collection ICollection Keys Returns the keys as a collection 33 Hashtables The hashtable is a common implementation of the IDictionary interface If the key is not an integer then the hashcode for the key is used as an index into the hashtable Keys used with hashtables must have unique hashcode for every value 34 IDictionaryEnumerator Interface This is the type of enumerator used with dictionaries It implements IEnumerator Has properties Key Returns the key for the item Value Returns the value for the item 35 BitArray Class Long bit strings can be difficult to store efficiently Since data structures can be addressed on the byte level, we end up storing one bit per byte, wasting 7 bits The BitArray class stores the bits efficiently while providing access 36 BitArray Class The constructor is overloaded BitArray(Boolean[]) Makes a BitArray from an array of Booleans BitArray(Byte[]) Makes an array from an array of Bytes where each byte represents 8 bits BitArray(int len) Creates a BitArray of len bytes BitArray(int[]) Makes a BitArray from the 32 bits in each int in an array of ints 37 BitArray Indexer The BitArray has an indexer providing both get and set BitSet bs = new BitSet(8); bs[0] = true; Console.WriteLine(bs[1]); There are also Get and Set methods bool Get(int index) void Set(int index, bool value) 38 BitArray Operations Various Boolean operations are provided BitArray And(BitArray) BitArray Or(BitArray) BitArray Xor(BitArray) BitArray Not() You can set all of the bits at once void SetAll(bool value) 39 Contents Arrays Collections Generics Strings 40 Generics All of the containers so far have stored data as objects This means Containers hold any type Operations must test the type before operating on the objects in the container When objects are removed from the container they must be cast to their true type The programmer must remember the type of the object placed in the container CLR must test to see that the cast is legal 41 Generics All of this Places an extra burden on the programmer having to remember the types Introduces new potential sources of error Forces expensive run-time type checking What is needed is a way to make a class work with many types but Do so efficiently Enforce compile type strong type checking 42 Generics The solution is generics! This is almost the same as the template facility of C++ Classes and methods are parameterized with a type Every time the class or method is used with a new type, the compiler generates the code for that type and compiles it This allows strong type checking at compile time 43 Generic Classes To create a generic class, we parameterize it with one or more type parameters The parameter types can then be used as types within the class and will be replaced with the actual types used when the class instance is created 44 Generic Array A growable array which can hold any type class GenericArray<T> { T[] data; public GenericArray(int sz) { if (sz < 1) sz = 1; data = new T[sz]; } … } * see GenericArray 45 Creating Generic Class Instances To create an instance of our generic array for integers GenericArray<int> iar = new GenericArray<int>(5); This will cause the compiler to write a new class and replace every occurrence of the parameter T by int and compile this new class 46 Generic Methods A class can also have generic methods which can work with any type We will demonstrate this by writing a method to test the Generic Array This method will be placed in the class containing the Main method 47 Generic Methods static void test<E>(string id, GenericArray<E> ar, E[] data) { for (int i = 0; i < data.Length; i++) { ar[i] = data[i]; } for (int i = 0; i < data.Length; i++) { Console.WriteLine("{0}[{1}] = {2}", id, i, ar[i]); } Console.WriteLine("final capacity={0}", ar.Capacity); } 48 Generic Collections There are actually three different namespaces for collections System.Collections Non-generic collections with data stored as objects System.Collections.Generic Generic collections System.Collections.Specialized Specialized, strongly typed collections designed to work efficiently with specific types 49 Generic Collections Generic Class Description Dictionary<K, V> Generic unordered dictionary LinkedList<E> Generic doubly linked list List<E> Generic ArrayList Queue<E> Generic queue SortedDictionary<K, V> Generic dictionary implemented as a tree so that elements are stored in order of the keys SortedList<K, E> Generic binary tree implementation of a list. Can have any type of subscript. More efficient than SortedDictionary in some cases. Stack<E> Generic stack 50 Contents Arrays Collections Generics Strings 51 Strings C# strings are really instances of System.String The class implements IComparable, ICloneable, IConvertable, IEnumerable, IEnumerable<string>, IComparable<string>, IEquatable The class provides a large number of methods for manipulating strings 52 Creating Strings The easiest way is to assign a string in quotes string s = “abc”; All builtin types have a ToString() method which can be used to convert to a string int n = 5; string s1 = n.ToString(); Verbatim strings start with an @ symbol and do not have escape characters replaced string exact = @”ab\nc” 53 Manipulating String Contents Strings are immutable This means that any attempt to change a string will create a new string This has major performance implications If you will be making major changes to a string, you should use a StringBuilder 54 Accessing String Contents Strings have an indexer which supports get only String s = “abc”; Console.WriteLine(s[1]); There is also a substring method Substring(int startIdx); Substring(int start, int len); Find the string length with Length property Length 55 Comparing Strings A static method to compare two strings static An instance method to compare this to another string int int compare(string, string); CompareTo(string); Static & instance versions of Equals int Equals(string) static bool Equals(string, string) 56 Comparing Strings Comparing the starts and ends of strings bool startsWith(string) bool endsWith(string) 57 Searching Strings To find the first index of a char To find the first index of a string int IndexOf(string) int IndexOf(string, int startIndex) To find the last index of a char int IndexOf(char) int IndexOf(char, int startIndex) int LastIndexOf(char) int LastIndexOf(char, int startIndex) To find the last index of a string int LastIndexOf(string) int LastIndexOf(string, int startIndex) 58 Searching Strings Find the first occurrence of any of a set of characters int IndexOfAny(char[]) int IndexOfAny(char[], int startIndex) Find the last occurrence of any of a set of characters int LastIndexOfAny(char[]) int LastIndexOfAny(char[], int startIndex) 59 Handling Spaces To remove a set of chars from start or end To remove spaces from both ends Trim() To remove a set of chars from both ends TrimStart(chars[]) TrimEnd(chars[]) Trim(char[]) To pad spaces on either side PadRight(int totalLength) PadLeft(int totalLength) 60 Converting Case ToUpper() ToLower() 61 Splitting and Joining To split a string into an array of strings at every occurrence of a separator char string[] split(string, char[]) To join an array of strings into one string with a separator string between every pair of string string join(string sep, string[]) 62 Formatting To format an object into a string string format(string fmt, object) The format string is the same as used by WriteLine where an argument is referenced by an index string Where s = s1.format(“{0:fmt}”, i); fmt is one of the format codes on the next page 63 Formatting Format C D F E P X D Meaning Currency Decimal Fixed point Scientific Percent Hexadecimal Long date 64 StringBuilder Class The trouble with strings is that they are immutable Every time you have to concatenate two strings, a new string is produced This creates a huge amount of memory allocation and garbage collection The StringBuilder is a class which can build a string much more efficiently 65 StringBuilder Class To create one StringBuilder() StringBuilder(int capacity) If the capacity of the StringBuilder is exceeded, new space is automatically allocated Ensuring sufficient capacity at the start is more efficient than forcing reallocation 66 Appending to a StringBuilder StringBuilder Append(anyPrimitive) This produces a string representation of the primitive and appends it onto the end of the contents of the StringBuilder This can be used to append strings too You can also append a formatted string similar to the formatting done by WriteLine sb.AppendFormat("2) {0}, {1}", var1, var2); 67 Appending to a StringBuilder You can also append a line using the default line terminator AppendLine() AppendLine(string) Without a parameter, it just inserts a line terminator With a parameter, the string is appended followed by the line terminator 68 Getting the Content Building a string is useless unless you can retrieve it To get the whole StringBuffer string ToString() To get just part of the StringBuffer string ToString(int start, int len) 69