裁剪字符串数组中的第一个元素,而不将所有元素复制到新数组中

本文关键字:元素 数组 复制 新数组 字符串 第一个 裁剪 | 更新日期: 2023-09-27 18:29:33

有一个字符串数组

string[] lines

我想删除第一个元素。因此,如果数组有5个元素,我希望最终得到4个。

有很多方法可以实现这一点:

  1. 创建一个新的字符串数组,其大小与原始数组的大小相同。然后简单地复制所有元素(第一个元素除外)。我不喜欢这样,因为,好吧,你必须制作一个全新的数组,并且似乎重复了内存使用情况(?)

  2. 使用像List这样的集合来实现此操作的方法。但情况也是如此:我必须将字符串数组转换为列表,然后删除第一个元素,然后将列表转换为字符串数组(因为我需要字符串数组,而不是列表)。

  3. System.Array.Resize()似乎能够"裁剪"数组,这正是我所需要的。然而,它裁剪了"最右边"的元素,而我需要裁剪第一个(最左边)元素。


我的问题是:有没有一种更简单的方法可以消除字符串数组中的第一个元素,最终得到一个大小比原来的小一的数组?

裁剪字符串数组中的第一个元素,而不将所有元素复制到新数组中

我不知道你想用"裁剪"版本做什么,但一个非常便宜的方法是在ArraySegment<>中顶部包裹lines,就像这样:

  var cropped = new ArraySegment<string>(lines, 1, 4);

自.NET 4.5(2012年起)以来,ArraySegment<>实现了一些接口,因此您可以执行以下操作:

  foreach (var l in cropped)
  {
      // ...
  }

(在ArraySegment<>上使用显式接口实现,迭代变量l是强类型的)。

请记住,这只是原始数组实例的包装器。如果修改了该数组,则会在ArraySegment<>中反映出来。没有复制(甚至没有一个肤浅的复制)。


如果需要索引等,请将ArraySegment<>结构的值框为IReadOnlyList<>IList<>:

  IReadOnlyList<string> croppedB = new ArraySegment<string>(lines, 1, 4);

或:

  IList<string> croppedC = new ArraySegment<string>(lines, 1, 4);

如果你真的喜欢这个整体"不要创建一个新数组",你可以使用startIndex和长度变量,并始终保持整个数组的原样,只通过这两个值将其一部分标记为可用。但是,如果你不喜欢大阵列大小和边缘性能,如果你只创建一个新阵列,你的程序看起来会更干净,更容易理解、创建和维护:

var arrayMinusFirstElement = lines.Skip(1).ToArray()

此解决方案模拟一个数组,您可以在末尾添加项,并从开始裁剪项。无论添加或裁剪了多少项,都可以始终使用基于零的索引器。它是一个队列,您可以修改它的元素并通过它们的索引访问它们。

var lines = new DicAsArray<string>();
lines.Add("zero");
lines.Add("one");
lines.Add("two");
lines.Add("three");
lines.Add("four");
lines.Crop();
lines[2] = "!!!";
for (int i = 0; i < lines.Count; i++)
{
    Console.WriteLine(lines[i]);
}

剩下的就像

public class DicAsArray<T>
{
    public DicAsArray()
    {
        _dic = new Dictionary<int, T>();
        _minIndex = 0;
        _maxIndex = -1;
    }
    public void Add(T item)
    {
        _dic[++_maxIndex] = item;
    }
    public T Crop()
    {
        _croppedCount++;
        var item = _dic[_minIndex];
        _dic.Remove(_minIndex++);
        return item;
    }
    public T this[int index]
    {
        get
        {
            var mappedIndex = _croppedCount + index;
            return _dic[mappedIndex];
        }
        set
        {
            var mappedIndex = _croppedCount + index;
            if (mappedIndex > _maxIndex || mappedIndex < _minIndex)
                throw new IndexOutOfRangeException();
            _dic[mappedIndex] = value;
        }
    }
    public int Count { get { return _dic.Count; } }
    private Dictionary<int, T> _dic;
    private int _maxIndex;
    private int _minIndex;
    private int _croppedCount;
}

您说Array.Resize()裁剪最右边的元素,然后简单地先反转数组,然后再反转。

Array.Reverse(Array.Resize(Array.Reverse(myArray)))