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);
}
-
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\$John Alexiou– John Alexiou2023年04月21日 20:33:04 +00:00Commented Apr 21, 2023 at 20:33
-
1\$\begingroup\$ Do the "groups" possibly overlap? What is to happen if they do? \$\endgroup\$greybeard– greybeard2023年04月22日 12:02:30 +00:00Commented 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– greybeard2023年04月23日 11:15:51 +00:00Commented 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– Ill Magnus2023年04月23日 20:15:16 +00:00Commented Apr 23, 2023 at 20:15
-
\$\begingroup\$ @greybeard I didn't understand what you explained \$\endgroup\$Ill Magnus– Ill Magnus2023年04月23日 20:17:27 +00:00Commented Apr 23, 2023 at 20:17
1 Answer 1
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);
}