-1

How to swap two different-length groups of variables of the same array in the same array? Even if I need the code in C#, in the meantime the theoretical procedure would be enough for me.

I've already tried several methods, but I was looking for a less redundant and\or less heavy.

for example I have string[] lines with these lines:

line 0
line 1
line 2
line 3
line 4
line 5
line 6
line 7
line 8

If you want to swap lines 1 2 3 with lines 5 6 this should look like this:

line 0
line 5
line 6
line 4
line 1
line 2
line 3
line 7
line 8

n.b. : each time which and how many lines to swap are different.

Here I put my code: Swap two different length group of variable in array.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
  • 2
    Please show your work and explain what is working or not working. If you have working code and are just looking for feedback to improve it, consider posting to https://codereview.stackexchange.com/. – Jimmy Apr 21 '23 at 16:26
  • Start by writing a the function header for a method that will do the work for you. – Joel Coehoorn Apr 21 '23 at 16:52
  • You have 4 pieces of information, the two offsets and two lengths. Or is there some other way you specify _what_ to swap? – John Alexiou Apr 21 '23 at 17:55
  • @JohnAlexiou i have 2 startIndex and 2 length – Ill Magnus Apr 21 '23 at 20:27
  • @IllMagnus - it wold benefit you to put this functionality into a function and then you can try it out under different inputs easier. – John Alexiou Apr 21 '23 at 20:30

3 Answers3

0
public static class Extension
{
    public static string[] Shift(this string[] array, int startIndex, int length, int newIndex)
    {
        string[] items = array.Skip(startIndex).Take(length).ToArray();
        ArrayList arrayList = new ArrayList(array);
        arrayList.RemoveRange(startIndex, length);
        arrayList.InsertRange(newIndex, items);

        arrayList.CopyTo(array);
        return array;
    }
}

private static void Main(string[] args)
{
    string[] array =
        {
        "line 0",
        "line 1",
        "line 2",
        "line 3",
        "line 4",
        "line 5",
        "line 6",
        "line 7",
        "line 8"
    };
    array = array.Shift(5, 2, 1);
    array = array.Shift(3, 3, 4);
}

Could do it with an extension class. Not fully tested.

ccStars
  • 817
  • 2
  • 11
  • 34
  • 1
    Why in the year 2023 would anyone use `ArrayList` ?!? The .NET gods invented `List` for a reason. – John Alexiou Apr 21 '23 at 17:53
  • it's a heavy bag compared to mine, although much easier to understand and write. (mine takes 1 ms, yours 62 ms). here i put my code https://codereview.stackexchange.com/questions/284597/swap-two-different-length-group-of-variable-in-array-vs-c – Ill Magnus Apr 21 '23 at 20:10
0

With results

0,1,2,3,4,5,6,7,8,9,10
0,8,9,5,6,7,1,2,3,4,10

I have the following code:

internal class Program
{
    static void Main(string[] args)
    {
        int[] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        Console.WriteLine(string.Join(",", array));

        SwapElements(ref array, 1..5, 8..10);

        Console.WriteLine(string.Join(",", array));
    }

    static void SwapElements<T>(ref T[] array, Range a, Range b)
    {
        (int a_Offset, int a_Length) = a.GetOffsetAndLength(array.Length);
        (int b_Offset, int b_Length) = b.GetOffsetAndLength(array.Length);

        if (a_Offset > b_Offset)
        {
            ((b_Offset, b_Length), (a_Offset, a_Length)) = ((a_Offset, a_Length), (b_Offset, b_Length));
        }

        Range pre_a = Range.EndAt(a_Offset);
        a = new Range(a_Offset, a_Offset + a_Length);
        Range between = new Range(a_Offset + a_Length, b_Offset);
        b = new Range(b_Offset, b_Offset + b_Length);
        Range post_b = Range.StartAt(b_Offset + b_Length);

        array = Concat(array[pre_a], array[b], array[between], array[a], array[post_b]);
    }

    /// <summary>
    /// Concatenates two or more arrays into a single one.
    /// </summary>
    /// <remarks>
    /// Code taken from https://stackoverflow.com/a/52749536/380384
    /// </remarks>
    public static T[] Concat<T>(params T[][] arrays)
    {
        // return (from array in arrays from arr in array select arr).ToArray();

        var result = new T[arrays.Sum(a => a.Length)];
        int offset = 0;
        for (int x = 0; x < arrays.Length; x++)
        {
            arrays[x].CopyTo(result, offset);
            offset += arrays[x].Length;
        }
        return result;
    }
}

Notes.

  1. I am using Range objects to define the array slices to be swapped. I use a custom Concat function stolen from [SO] to re-assemble the array from the different slices. An ordering of the slices is done before the operation to ensure the elements between the two slices are defined properly.

  2. C# Ranges use some obscure notion defining a range from start to end as start..(end+1) for some reason. 70 years ago Fortran did the same with start:end that made sense, and every other vector language since (like Matlab etc), yet when C# introduced slices, they completely foobar'd in order to make it Python-like for no good reason. End of rant.

John Alexiou
  • 28,472
  • 11
  • 77
  • 133
0
public static T[] Swap<T>(this T[] array, int startIndexA, int lengthA, int startIndexB, int lengthB) 
{
    List<T[]> arrays = new List<T[]>();

    if(startIndexA > startIndexB)
    {
        int tempIndex = startIndexA;
        int tempLength = lengthA;

        startIndexA = startIndexB;
        lengthA = lengthB;

        startIndexB = tempIndex;
        lengthB = tempLength;
    }

    var sliceA = array[startIndexA..(startIndexA + lengthA)];
    var sliceB = array[startIndexB..(startIndexB + lengthB)];


    if (startIndexA > 0)
        arrays.Add(array[0..startIndexA]);

    arrays.Add(sliceB);

    if (startIndexA + sliceA.Length < startIndexB)
        arrays.Add(array[(startIndexA + sliceA.Length)..startIndexB]);

    arrays.Add(sliceA);

    if ((startIndexB + sliceB.Length) < array.Length)
        arrays.Add(array[(startIndexB + sliceB.Length)..]);

    return arrays.SelectMany(a => a).ToArray();
}

Call it in the following way

string[] array =
            {
            "line 0",
            "line 1",
            "line 2",
            "line 3",
            "line 4",
            "line 5",
            "line 6",
            "line 7",
            "line 8"
        };
    var result = array.Swap(5, 2, 1, 3);
ccStars
  • 817
  • 2
  • 11
  • 34