如何在同一个数组中交换同一个数组的两个不同长度的变量组?即使我需要 C# 中的代码,同时理论过程对我来说就足够了。
我已经尝试了几种方法,但我一直在寻找一种不那么多余和/或不那么重的方法。
例如我有
string[] lines
这些行:
line 0
line 1
line 2
line 3
line 4
line 5
line 6
line 7
line 8
如果你想用第 5 6 行交换第 1 2 3 行,这应该是这样的:
line 0
line 5
line 6
line 4
line 1
line 2
line 3
line 7
line 8
n.b. : 每次要交换的行和行数都是不同的。
我把我的代码放在这里:交换数组中两个不同长度的变量组.
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);
}
可以用扩展类来做。没有经过全面测试。
有结果
0,1,2,3,4,5,6,7,8,9,10
0,8,9,5,6,7,1,2,3,4,10
我有以下代码:
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;
}
}
笔记。
我正在使用
Range
对象来定义要交换的数组切片。我使用从 [SO] 窃取的自定义 Concat
函数从不同的切片重新组装数组。在操作之前对切片进行排序,以确保正确定义两个切片之间的元素。
C# 范围出于某种原因使用一些晦涩的概念将
start
到 end
的范围定义为 start..(end+1)
。 70 年前,Fortran 对 start:end
做了同样的事情,这是有道理的,此后的所有其他矢量语言(如 Matlab 等),但是当 C# 引入切片时,他们完全 foobar'd 以使其无缘无故地像 Python .吐槽完毕
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();
}
按如下方式调用
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);