2014-11-06 87 views
4

有一个字符串数组裁剪一个字符串数组的第一个元素没有所有的元素复制到新阵列

string[] lines 

我想删除第一个元素。因此,如果数组有5个元素,我想用4

落得有多种方式来实现这一目标:

  1. 创建一个新的字符串数组,与同尺寸的原减一。然后简单地复制所有元素(除了第一个元素)。我不喜欢这个,因为你需要制作全新的阵列并且看起来重复了内存使用(?)

  2. 使用像List这样的集合来实现这个方法。但是,那么这将是同样的故事:我会到我的字符串数组转换到一个列表,然后取出第一个元素,则列表转换为字符串数组(因为我需要一个字符串数组,而不是一个列表)。

  3. System.Array.Resize()似乎能够“裁剪”阵列,而这正是我需要的。但是,它会裁剪“最右边”的元素,而我需要裁剪第一个(最左边的)元素。


我的问题是:是否有一个更简单的消除字符串数组的第一个元素,用一个数组,其大小是一个小于原来的结束了呢?

+1

AFAIK数组是不可变的。 'System.Array.Resize()'通过使用选项1来实现。 – 2014-11-06 08:10:01

+0

如果你确实需要这个,你可能需要一个CircularBuffer。正如谷歌将证明的那样,C#的实现有很多。 – Joe 2014-11-06 08:15:31

+0

不,你不能复制..你最好能做的是(),创建一个自定义类,其中 – 2014-11-06 08:56:14

回答

6

我不知道你想使用“裁剪”版本是什么,但很便宜的事情是顶部包裹linesArraySegment<> ,像这样:

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); 
+3

这很简洁,在.NET 4.5之前,这个结构并没有任何意义,因为它只是在偏移和长度上进行的,而且你必须自己进行偏移计算。我想知道他们为什么不创建一个构造函数,它使用'IList '来嵌套它们。做一个完全只读的变体会更有意义,恕我直言。 – Groo 2014-11-06 09:01:25

+0

对于ArraySegment为+1。你永远不要停止学习。最终可能会派上用场,thx。 – 2014-11-06 11:33:14

2

如果你真的到这整个“不创建一个新的数组”你可以使用一个startIndex和长度变量,总是有你的整个阵列,因为它只有通过标志着这两个值可用它的一部分。但是,如果你不进大阵尺寸和最边缘的性能,你的程序看起来会更加清晰,会更容易理解,创建和维护,如果你只是创建一个新的数组:

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

这不是“消除数组中的第一个元素”。 – dotctor 2014-11-06 09:05:01

+0

@HamidP不,因为从数组中删除元素而不创建临时对象是不可能的。数组是固定的。您可以使用我描述的方式,或者使用我临时发布的密码。任何其他解决方案(包括你的)都只是隐藏了临时创建。但*隐藏*这不是问题的要点,OP询问*避免*它。 – nvoigt 2014-11-06 09:11:49

+0

我的解决方案如何隐藏“临时创建”? – dotctor 2014-11-06 09:16:02

1

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

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; 
} 
+0

堆栈溢出不鼓励在没有附带说明的情况下发布代码。例如,你可能会提到这种实现方式效率非常低,与“队列”相比。另外,它可能是'_dic.Remove(_minIndex ++)'? – Groo 2014-11-06 08:41:02

+0

我正在路上,等一下。 – dotctor 2014-11-06 08:44:24

+0

它不是'Queue','Queue'没有索引器。 @Groo – dotctor 2014-11-06 08:50:36

0

你说Array.Resize()作物最右边元素,那么只需先倒转数组,然后将其颠倒过来。

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

相关问题