How to improve this array manipulation function? The function takes 2 arguments: array: int[], cap: int

Members would be ranged from 0 to cap.

e.g.

array = [0,0,0,2,6,3,0,4,2,4,0]
cap = 6


The return value is a new array of same length based on these rules:


The function can only change values of consecutive elements which are > 0.  i.e. any where the original array has 0, the new array has 0 as well.
In a consecutive series of elements which are > 0, if the maximum of it equals cap, then in the new array they are changed to 1,1,...,1,cap of the same length. e.g.  0,2,6,4,0 -> 0,1,1,6,0
In a consecutive series of elements which are > 0, if the maximum of it is smaller than cap, then the elements in the new array are mapped to either 1 or maximum  (if the element value &lt; maximum then 1, otherwise maximum ) . e.g.  0,2,5,5,0 -> 0,1,5,5,0


So the sample array would map to [0,0,0,1,1,6,0,4,1,4,0]

The following are my code which are implemented in both languages, it surprises me that F# takes same lines as C#.

I would like to suggestions to improve either language.

F#

open System

let private reorder cap (array: int[]) =
    if Array.isEmpty array then
        array
    else
        let max = array |&gt; Array.max
        if max = cap then
            let newArray = Array.create array.Length 1
            newArray.[array.Length-1] &lt;- cap
            newArray
        else
            array |&gt; Array.map (fun elem -&gt; if elem = max then max else 1)

let private getZeroes todo = 
    todo |&gt; Seq.takeWhile (fun elem -&gt; elem = 0)
         |&gt; Seq.toArray

let private getNumbers todo cap =
    todo |&gt; Seq.takeWhile (fun elem -&gt; elem &lt;&gt; 0)
         |&gt; Seq.toArray
         |&gt; reorder cap

let GetEquivalentPermutation (array: int[], cap) =

    let rec joinParts finished todo =
        if Seq.isEmpty todo then finished |&gt; Seq.toArray
        else
            let zeroes = getZeroes todo
            let nextTodo = todo |&gt; Seq.skip zeroes.Length
            let numbers = getNumbers nextTodo cap
            let finalTodo = nextTodo |&gt; Seq.skip numbers.Length
            let newFinished = Seq.append (Seq.append finished zeroes) numbers
            joinParts newFinished finalTodo

    joinParts [] array


C#

    static int[] EquivalentOutput(int cap, int[] permutation)
    {

        IEnumerable&lt;int&gt; right = permutation;
        List&lt;int&gt; equivalentLine = new List&lt;int&gt;();

        while (right.Any())
        {
            var leftArray = right.TakeWhile(x =&gt; x != 0).ToArray();

            List&lt;int&gt; leftEquivalent;
            if (leftArray.Length == 0)
            {
                leftEquivalent = new List&lt;int&gt;();
            }
            else if (leftArray.Length != 1)
            {
                int max = leftArray.Max();
                if (max == cap)
                {
                    leftEquivalent = leftArray.Take(leftArray.Length - 1).Select(x =&gt; 1).ToList();
                    leftEquivalent.Add(cap);
                }
                else
                {
                    leftEquivalent = leftArray.Select(x =&gt; x &lt; max ? 1 : max).ToList();
                }
            }
            else
            {
                leftEquivalent = leftArray.ToList();
            }
            equivalentLine.AddRange(leftEquivalent);
            equivalentLine.AddRange(right.SkipWhile(x =&gt; x != 0).TakeWhile(x =&gt; x == 0));
            right = right.SkipWhile(x =&gt; x != 0).SkipWhile(x =&gt; x == 0);

        }
        return equivalentLine.ToArray();
    }
Seems you might be overusing Linq since you are manipulating an array.  Here is an example that to me is a bit more readable (although the readability could be improved further) and it is faster.

private static int[] EquivalentOutput(int cap, int[] permutation)
{
    int[] copy = permutation.ToArray();

    for (int i = 0; i &lt; copy.Length; i++)
    {
        if (copy[i] == 0)
            continue;

        var consecutiveElements = copy.Skip(i).TakeWhile(x =&gt; x != 0).ToArray();
        var max = consecutiveElements.Max();
        if (max == cap)
        {
            for (int j = 0; j &lt; consecutiveElements.Length - 1; j++)
                copy[i++] = 1;
            copy[i++] = cap;
        }
        else
        {
            for (int j = 0; j &lt; consecutiveElements.Length; j++)
                copy[i] = copy[i++] == max ? max : 1;
        }
    }
    return copy;
}


Update:
@svick pointed out that it feels a bit "weird" changing the loop variable inside the loop so I am providing an alternative which some people will consider easier to read...

private static int[] EquivalentOutput(int cap, int[] permutation)
{
    int[] copy = permutation.ToArray();

    int i = 0;
    while (i &lt; copy.Length)
    {
        if (copy[i] &gt; 0)
        {
            var consecutiveElements = copy.Skip(i).TakeWhile(x =&gt; x != 0).ToArray();
            var max = consecutiveElements.Max();
            if (max == cap)
            {
                for (int j = 0; j &lt; consecutiveElements.Length - 1; j++)
                    copy[i++] = 1;
                copy[i++] = cap;
            }
            else
            {
                for (int j = 0; j &lt; consecutiveElements.Length; j++)
                    copy[i] = copy[i++] == max ? max : 1;
            }
        }

        i++;
    }
    return copy;
}