C#: Splicing array
Let's say I have a long[]
called IDs
with a few elements in the array.
What's the easiest way to splice into/insert a new element at a given index?
Right now I'm doing this, and I don't think it's optimal:
long[] IDs = ...;
var IDsList = IDs.ToList();
IDsList.Insert(newId, indexToIn开发者_如何学JAVAsertAt);
IDs = IDsList.ToArray();
There's nothing built-in into the Array
class?! This strikes me as very odd, coming from the JavaScript world of [].splice()
.
Use a List<long>
instead of the array since you're needing to make inserts.
It might seem a bit odd, but probably it was left out to prevent developers from writing code with bad performance too easily. (If you're inserting a new item in the middle, you probably want a resizable collection like List<T>
.) The only way to "insert" into a fixed-size collection like an Array
is to copy the collection's contents into a new collection and put the item there. Obviously this is not the best idea if you're performing a lot of insertions.
If the use of a T[]
array is outside your control, and insertion is necessary, copying the array yourself is at least preferable to the code you have, as it saves you two costly operations: a copy and an insertion, which requires that potentially many elements be "shifted" by one index. (Your current solution copies the contents of the long[]
into a List<long>
, then inserts an item into that List<long>
, then copies that List<long>
back into a new long[]
.)
In this case (the choice of a T[]
is not negotiable), you might consider an extension method to do what I just described above. This way at least you have a reusable piece of code for scenarios when you do need this behavior. Something like:
public static class ArrayHelper
{
public static T[] Insert<T>(this T[] source, int index, T item)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
if (index < 0 || index > source.Length)
{
throw new ArgumentOutOfRangeException("index");
}
// Allocate a new array with enough space for one more item.
T[] result = new T[source.Length + 1];
// Copy all elements before the insertion point.
for (int i = 0; i < index; ++i)
{
result[i] = source[i];
}
// Insert the new value.
result[index] = item;
// Copy all elements after the insertion point.
for (int i = index; i < source.Length; ++i)
{
result[i + 1] = source[i];
}
return result;
}
}
Notice that the above is considerably more efficient than what you have now, as it only needs to perform the equivalent of a full array copy one time (not twice), and it also doesn't require any intermediate "shifting" of elements.
Usage:
int[] numbers = new int[] { 2, 3, 4 };
numbers = numbers.Insert(0, 1);
foreach (int number in numbers)
{
Console.WriteLine(number);
}
Output:
1 2 3 4
Having to do something similar, here's what I've come up with, similar to Dan Tao's:
T[] newArr = new T[oldArr.Length+1];
//copy first part of the array, starting with newArr[0] <- oldArr[0], up to the insertion point
System.Array.Copy(oldArr, 0, newArr, 0, insertIndex, insertIndex);
//insert new element
newArr[insertIndex] = spliceElem;
//copy the rest of the array, from newArr[insert+1] <- oldArr[insert] to the end
System.Array.Copy(oldArr, insertIndex, newArr, insertIndex + 1, oldArr.Length-insertIndex);
return newArr;
You could try with
IDs.SetValue(newId, indexToInsertAt);
More here
精彩评论