#154 – Using an Invalid Array Index Causes an Exception to Be Thrown

If you try to reference an array element using an index that is outside the declared range of the array, an IndexOutOfRangeException exception will be thrown.

            int[] scores = { 88, 99, 79, 88};
            Console.WriteLine("5th element? - {0}", scores[4]);    // IndexOutOfRangeException

#153 – Returning a Subset of Array Elements Matching a Particular Criteria

Because System.Array implements the IEnumerable interface and because LINQ extends IEnumerable, you can use the IEnumerable.Where method on arrays to find a subset of elements that match a particular criteria.

The Where method accepts a delegate to a function that takes a single element of the same type as the array and returns a boolean value, indicating whether a match is found.  Where returns an IEnumerable collection, which can be iterated on to get the elements in the subset.

Here’s an example, finding the set of passing scores in a set of scores.

            int[] scores = { 89, 98, 72, 100, 68 };

            // Count number of passing grades
            int numPassed = scores.Where((Func<int,bool>)IsPassingGrade).Count();

Here’s the implementation of IsPassingGrade.

        static bool IsPassingGrade(int score)
        {
            return (score >= 75);
        }

You can avoid defining a separate function by using a lamba expression.

            int numPassed = scores.Where(s => s >= 75).Count();

Similar to Array.FindAll.

#152 – Remove Duplicate Array Entries Using Distinct() Method

You can use the IEnumerable.Distinct method on an array to get all of the elements of the array, with the duplicates removed.

This method returns a result of the type IEnumerable<T>, where T is the type of the element in the array.  You can iterate through this new list using the foreach statement, or count the number of elements using the Count method.

            int[] scores = { 88, 99, 79, 88, 78, 100, 79 };

            // # of unique scores
            Console.WriteLine("# unique = {0}", scores.Distinct().Count());   // 5

            // List only the unique scores
            foreach (int next in scores.Distinct())
                Console.WriteLine("Score : {0}", next);

#151 – Determining Whether an Array Contains a Specific Element

You can use the Array.Find method to find a particular element in an array.  If, however, you only care whether a particular element is present in an array, you can use the IEnumerable.Contains method.  The Contains method returns true if the element was found in the array, false if not.

            int[] scores = { 89, 98, 72, 100, 83 };

            bool someoneAcedIt = scores.Contains(100);   // true

Contains also works on arrays holding objects belonging to a custom type.

            Person[] folks = new Person[3];
            folks[0] = new Person("Bronte", "Emily", 29);
            folks[1] = new Person("Bronte", "Charlotte", 31);
            folks[2] = new Person("Tennyson", "Alfred", 24);

            bool foundAlfred = folks.Contains(new Person("Tennyson", "Alfred", 24));

This will only work as expected if the underlying type has implemented the equality operator in a way that properly compares two objects to determine if they are equal.  If the equality operator has not been defined, only the references to the objects will be compared, rather than the contents of the objects.

#150 – Other Aggregate Functions You Can Apply to Numeric Arrays

Post #147 mentioned using IEnumerable.Average to get the average of an array of numeric values.  The System.Linq namespace includes several other extension methods for IEnumerable that can be used to aggregate values:

  • Max – Get the maximum value
  • Min – Get the minimum value
  • Sum – Get the sum of all values
            int[] scores = { 89, 98, 72, 100, 83 };
            int sum = scores.Sum();        // 442
            int min = scores.Min();        // 72
            int max = scores.Max();        // 100
            double avg = scores.Average();       // 88.4

#149 – Using IEnumerable.Aggregate to Perform a Calculation Based on All Elements in an Array

IEnumerable.Average can be used to perform an average across all elements in an array.  Instead of doing an average, we can perform our own custom calculation across all elements, using the IEnumerable.Aggregate function.

Aggregate works by specifying a function that will get called once for each element in the array (except for the first element).  The function’s arguments are:

  • On 1st pass: 1st and 2nd elements are passed to the function
  • On 2nd thru (n-1)th pass: result of previous pass is passed as 1st parameter, next element as 2nd parameter

The return value is used to store the result of your aggregate function and is passed back to the function on the next pass.

Here’s an example:

        public static Person CombinePeople(Person prevResult, Person next)
        {
            return new Person(prevResult.FirstName + next.FirstName,
                prevResult.LastName + next.LastName,
                prevResult.Age + next.Age);
        }

        // Example of calling Aggregate
        Person pCombined = folks.Aggregate((Func<Person,Person,Person>)CombinePeople);

#146 – Using Array.FindAll to Find a Set of Matching Elements in an Array

Instead of using Array.Find to find the first matching element in an array, you can use Array.FindAll to find all elements that match a particular set of criteria.  If no elements match, FindAll returns null.

Here we search for the Bronte sisters in an array of people:

            Person[] folks = new Person[4];
            folks[0] = new Person("Bronte", "Emily");
            folks[1] = new Person("Bronte", "Charlotte");
            folks[2] = new Person("Tennyson", "Alfred");
            folks[3] = new Person("Bronte", "Ernie");

            // Finds Emily and Charlotte but not Ernie
            Person[] brontes = Array.FindAll(folks, IsABronteSister);

Here is the function that looks for a match:

        static bool IsABronteSister(Person p)
        {
            string[] firstNames = { "Emily", "Charlotte", "Anne" };

            return (p.LastName == "Bronte") && (firstNames.Contains(p.FirstName));
        }

#145 – Using Array.Find to Search an Unsorted Array

You can use Array.BinarySearch to search a sorted array taking O(log n) time, but if you have an unsorted array, you can search it in O(n) time using the Array.Find method.

The Find method takes an array to search and a function that knows how to look for a match.  This matching function accepts a single element of the array and returns true or false, depending on whether a match is found.

Find returns a reference to the object in the array, or null if a match is not found.

        static void Main(string[] args)
        {
            Person[] folks = new Person[4];
            folks[0] = new Person("Bronte", "Emily");
            folks[1] = new Person("Bronte", "Charlotte");
            folks[2] = new Person("Tennyson", "Alfred");
            folks[3] = new Person("Mailer", "Norman");

            Person thereHeIs = (Person)Array.Find(folks, FindNorman);
            folks[3].LastName = "Mailman";
        }

        static bool FindNorman(Person p)
        {
            return ((p.FirstName == "Norman") && (p.LastName == "Mailer"));
        }

#139 – Using the Array.Clone Method to Make a Shallow Copy of an Array

You can use the Clone method to copy all of an array’s elements to a new array.  The arrays’ elements must be of the same type.  Each element of the source array is copied to the destination array.

If the arrays contain a value type, you can change values in the destination array after copying without impacting values in the source array.

But if the arrays contain a reference type, the references to the objects are copied, so the destination array will point to the same objects as the source array.  A change in any object will therefore be seen by both arrays. This is known as a shallow copy.

            Person[] folks1 = new Person[2];
            folks1[0] = new Person("Bronte", "Emily");
            folks1[1] = new Person("Bronte", "Charlotte");

            // Copy the folks1 array
            Person[] folks2 = (Person[])folks1.Clone();

            // Change name of person in folks1
            folks1[1].FirstName = "Elvis";

            // Note that object in folks2 has also changed
            Console.WriteLine(folks2[1].FirstName);     // Elvis

#137 – Sorting an Array Using an Independent Comparer Method

Instead of extending a type to implement IComparable to allow sorting, you can create a separate class that knows how to compare objects of that type and use the new class to do the sorting.

Here’s an example of sorting objects of type Person using a custom Compare method.  To start with, we define a new class that implements IComparer.

        public class PersonSorter : IComparer
        {
            public int Compare(object o1, object o2)
            {
                Person p1 = o1 as Person;
                Person p2 = o2 as Person;

                // Sort by LastName, then by FirstName (ignore case)
                int compare = p1.LastName.ToLower().CompareTo(p2.LastName.ToLower());
                if (compare == 0)
                    compare = p1.FirstName.ToLower().CompareTo(p2.FirstName.ToLower());

                return compare;
            }
        }

Now we can sort using this compare function by passing an instance of the IComparer class into the Sort method.

            Person[] folks = new Person[4];
            folks[0] = new Person("Bronte", "Emily");
            folks[1] = new Person("Bronte", "Charlotte");
            folks[2] = new Person("Tennyson", "Alfred");
            folks[3] = new Person("Mailer", "Norman");

            Array.Sort(folks, new PersonSorter());