Example #1
0
        /// <summary>
        /// Modifies the given array in-place such that true-valued and false-valued items (determined by <paramref name="predicate" />) are contiguous rather than intermixed
        /// </summary>
        public static void Partition <TValue>(
            this TValue[] values,
            Func <TValue, bool> predicate,
            out ArrayView <TValue> trueValues,
            out ArrayView <TValue> falseValues)
        {
            Contract.RequiresNotNull(values);
            Contract.RequiresNotNull(predicate);

            if (values.Length == 0)
            {
                trueValues  = ArrayView <TValue> .Empty;
                falseValues = ArrayView <TValue> .Empty;
                return;
            }

            int leftIndex  = 0;
            int rightIndex = values.Length - 1;

            // left and right indices will eventually meet (immediate for a single element array).
            while (rightIndex != leftIndex)
            {
                // Advance the left cursor to the next out-of-place false-value.
                // (but don't go past right; consider an all-true array meaning that the right cursor initially also points to a true value).
                while (leftIndex < rightIndex && predicate(values[leftIndex]))
                {
                    leftIndex++;
                }

                // Similarly for the right cursor - find the next out-of-place true-value
                while (leftIndex < rightIndex && !predicate(values[rightIndex]))
                {
                    rightIndex--;
                }

                // Swap the out-of-place pair (each is no longer out of place).
                if (leftIndex != rightIndex)
                {
                    TValue temp = values[leftIndex];
                    values[leftIndex]  = values[rightIndex];
                    values[rightIndex] = temp;

                    // We've established both loop conditions above:
                    //   leftIndex < rightIndex && predicate(values[leftIndex]) && !predicate(values[rightIndex])
                    // (due to the swap).
                    // So, we can advance one or both cursors to avoid re-evaluating their predicates on the next iteration.
                    leftIndex++;
                    if (leftIndex < rightIndex)
                    {
                        rightIndex--;
                    }

                    Contract.Assert(leftIndex <= rightIndex);
                }
            }

            Contract.Assert(
                leftIndex == rightIndex,
                "Loop terminates when left and right cursors meet; we then have a pivot which could go in either the true or false view.");
            int pivotIndex = leftIndex;

            // The true values are [0, pivot] or [0, pivot - 1].
            // Shift so that the true values are instead [0, pivot - 1]
            if (predicate(values[pivotIndex]))
            {
                pivotIndex++;
            }

            trueValues  = new ArrayView <TValue>(values, 0, pivotIndex);
            falseValues = new ArrayView <TValue>(values, pivotIndex, values.Length - pivotIndex);
        }