1
\$\begingroup\$

The code below swaps two different-length groups of variables of the same array in the same array.

Is there any other method to achieve this that is less heavy or less redundant?

    static void Main()
    {
        //posi 0 1 2 3 4 5 6 7 8 9 10
        //resu 0 8 9 5 6 7 1 2 3 4 10
        //swap   1 2 3 4       8 9
        /* working example
        int nelem1 = 4;
        int start1 = 1;

        int nelem2 = 2;
        int start2 = 8;
        */
        int[] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        int[] array2 = new int[11];

        int nelem1 = 4; //number of element of group 1
        int start1 = 1; //start position of group 1

        int nelem2 = 2; //number of element of group 2
        int start2 = 8; //start position of group 2

        if (start1 > start2) //if start2 is before to start1, swap variable
            (start1, start2, nelem1, nelem2) = (start2, start1, nelem2, nelem1);

        int i = 0;
        while (i < start1) //pos from 0 to 0 //here is where i write positions and values ​based on the values ​in the initial comment
        {
            array2[i] = array[i++]; //print 0
            //i++;
        }
        //how much for print group 2?
        //start from start1, print nelem2 time
        while (i < start1 + nelem2) //pos from 1 to 2
        {
            array2[i] = array[i + start2 - start1]; //print 8 9
                                                    //now pos to i, i = start1; start 2 is start for print group 2
            i++;
        }
        //how much for print from end of group 2 and start of group 1?

        //start 2 + nelem2 is where is stop to print group 1, -nelem1 is where is start to print
        while (i < start2 + nelem2 - nelem1) //pos from 3 to 5
        {
            array2[i]=array[i + nelem1 - nelem2]; //print 5 6 7
                                                  //now pos to i, i = start1+nelem2; start1 + nelem 1 is where start the value to print, -nelem2 for the space is already used
            i++;
        }

        //start2 + nelem2 is end of print all variation
        while (i <  start2 + nelem2) //pos from 6 to 9 
        {
            array2[i]= array[i + start1-start2-nelem2 + nelem1];//print 1 2 3 4 
                                                                //now pos to i, print from start1, in the start of while i = -(-start2-nelem2 + nelem1)
            i++;
        }

        while (i< array.Length)
            array2[i] = array[i++]; //print the rest

        foreach (int x in array2) Console.WriteLine(x);

    }
\$\endgroup\$
6
  • 1
    \$\begingroup\$ I see what you are doing and it is essentially a re-mapping of the indexes. But it would benefit you to use function definitions for each functional block of code. \$\endgroup\$ Apr 21, 2023 at 20:33
  • 1
    \$\begingroup\$ Do the "groups" possibly overlap? What is to happen if they do? \$\endgroup\$
    – greybeard
    Apr 22, 2023 at 12:02
  • \$\begingroup\$ I didn't find a reference for a once popular approach: assuming no overlaps, reverse from min(starts) to max(ends) and again from min(starts) to min(ends), from min(ends) to max(starts), and from max(starts) to max(ends): constant additional space, just two streams of write addresses at any one time. Given enough temporary memory, stash away the bigger of the outer blocks, copy the smaller one over, move the middle and copy back the bigger one. \$\endgroup\$
    – greybeard
    Apr 23, 2023 at 11:15
  • \$\begingroup\$ @greybeard theoretically there should be a check to avoid the overlap, because if it happens, with this code, one number repeats and another disappears. \$\endgroup\$
    – Ill Magnus
    Apr 23, 2023 at 20:15
  • \$\begingroup\$ @greybeard I didn't understand what you explained \$\endgroup\$
    – Ill Magnus
    Apr 23, 2023 at 20:17

1 Answer 1

1
\$\begingroup\$

I see everything stuffed into Main(), and no telling what it's about but to examine the source code.
Create business procedures and document them, starting with suggestive names for the function and parameters, if any.

Where you see the need to comment a name, double-check whether the name could be improved to be self-explanatory.

(For beginner level code,) I quite like the comments to processing steps/groups of statements/loops.
Some hold that every loop deserving a comment should be a function of its own.

The preamble reads swaps two different-length groups of variables of the same array in the same array.
In the implementation, I read array and array2.

(Caveat: I don't do C#, had little luck trying out "C# 7+" (tuple assignment) online. Would rather have used Array - failed.)
A for statement keeps handling control variables/doing stuff needed between iterations out of the way:

    int i;
    // copy non-moved prefix
    for (i = 0 ; i < start1 ; i++) {
        array2[i] = array[i];
    }
    // how much for print group 2?
    // start from start1, print nelem2 time
    for (int end = start1 + nelem2, offset = start2 - start1 ; i < end ; i++) {
        array2[i] = array[i + offset];  // copy 8 9
    }
// alternatively
    for (int end = start1 + nelem2, source = start2 ; i < end ; i++, source++) {
        array2[i] = array[source];  // copy 8 9
    }
  • but don't open code copying part of an array:
    System.Array.Copy(array,/* 0, */ array2,/* 0, */ start1);  // copy non-moved prefix
    System.Array.Copy(array, start2, array2, start1, nelem2);  // group 2

In place (same array, definition A: output space is input space) with an auxiliary array:

/** In array, swap the sub-arrays specified.
 *  @return array
 */
int[] SwapGroups(int[] array, int start1, int length1, int start2, int length2)
{
    if (start2 < start1) {  // if start2 is before to start1, swap
        (start1, length1, start2, length2) = (start2, length2, start1, length1);
    }
    int[] aux;
    const int
        end1 = start1 + length1,
        end2 = start2 + length2;
    if (length1 <= length2) {
        aux = new int[length2];
        System.Array.Copy(array, start2, aux, 0, length2);
        System.Array.Copy(array, start1, array, end2 - length1, length1);
        System.Array.Copy(array, end1, array, start1 + length2, lengthBetween);
        System.Array.Copy(aux, 0, array, start1, length2);
    } else {
        aux = new int[length1];
        System.Array.Copy(array, start1, aux, 0, length1);
        System.Array.Copy(array, start2, array, start1, length2);
        System.Array.Copy(array, end1, array, start1 + length2, lengthBetween);
        System.Array.Copy(aux, 0, array, end2 - length1, length1);
    }
}

Copy() with overlap is well defined, but the is core repetition between the branches of the last if-statement I found no decent remedy for.

"The double-reverse approach", In place
(same array, definition 1: output space is input space, constant additional space (= less heavy?):

/** In array, reverse the range specified.
 *  @return array
 */
int[] reverse(int[] array, int start, int end)
{
    for ( ; start < end ; start++, end--) {
        (array[start], array[end]) = (array[end], array[start]);
    return array;
}
/** In array, swap the ranges specified.
 *  @return array
 */
int[] SwapGroups(int[] array, int start1, int length1, int start2, int length2)
{
    const int
        end1 = start1 + length1,
        end2 = start2 + length2;
    reverse(array, start1, end1);
    reverse(array, end1, start2);
    reverse(array, start2, end2);
    return reverse(array, start1, end2);
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.