【问题标题】:Way to pad an array to avoid index outside of bounds of array error填充数组以避免索引超出数组错误范围的方法
【发布时间】:2012-09-24 21:03:03
【问题描述】:

当我查询它时,我希望列表中至少有 183 个项目,但有时我提取的结果会导致项目计数低于 183。我当前的修复应该在计数小于的情况下填充数组183.

if (extractArray.Count() < 183) {
    int arraysize= extractArray.Count();
    var tempArr = new String[183 - arraysize];
    List<string> itemsList = extractArray.ToList<string>();
    itemsList.AddRange(tempArr);
    var values = itemsList.ToArray();
    //-- Process the new array that is now at least 183 in length
}

但我的解决方案似乎不是最好的。我将不胜感激任何其他可以帮助确保我在提取时获得至少 183 个项目的解决方案。

【问题讨论】:

  • 你有没有想过只使用List&lt;string&gt; 而不是数组?
  • 您是如何处理它以使您获得索引越界错误? foreach 在这种情况下会不起作用吗?
  • @Prayos 我会再对您的评论进行 10 次投票,但系统不允许。 Kobojunkie,你为什么要使用数组 per se
  • 考虑到我们在 .NET API 中获得的出色集合类型,这看起来确实很有趣。我假设您将一个数组传递给一个执行 183 次的“for”循环?您无法控制此代码?
  • 我们不知道 183 项数组的 OP 要求的原因。切换到List&lt;&gt; 将无法满足此要求,无论它是什么。

标签: c# arrays data-structures indexoutofboundsexception


【解决方案1】:

我不能说我会推荐这个解决方案,但我不会让它阻止我发布它!不管他们愿不愿意承认,每个人都喜欢 linq 解决方案!

使用 linq,给定一个包含 X 个元素的数组,您可以生成一个包含 Y(在您的情况下为 183 个)元素的数组,如下所示:

  var items183exactly = extractArray.Length == 183 ? extractArray :
                        extractArray.Take(183)
                                    .Concat(Enumerable.Repeat(string.Empty, Math.Max(0, 183 - extractArray.Length)))
                                    .ToArray();

如果元素少于 183 个,则数组将用空字符串填充。如果元素超过 183 个,则数组将被截断。如果正好有 183 个元素,则按原样使用数组。

我并不是说这是有效的,也不是说它一定是个好主意。但是,它确实使用了 linq(yippee!),而且很有趣。

【讨论】:

    【解决方案2】:

    我可能会听从其他人的建议,并使用一个列表。使用“容量”构造函数来提高性能:

    var list = new List<string>(183);
    

    然后,每当您获得一个新数组时,请执行此操作(将“”替换为您用于填充数组的任何值):

    list.Clear();
    list.AddRange(array);
    // logically, you can do this without the if, but it saves an object allocation when the array is full
    if (array.Length < 183)
        list.AddRange(Enumerable.Repeat(" ", 183 - array.Length));
    

    这样,列表总是重用同一个内部数组,减少分配和 GC 压力。

    或者,您可以使用扩展方法:

    public static class ArrayExtensions
    {
        public static T ElementOrDefault<T>(this T[] array, int index)
        {
            return ElementOrDefault(array, index, default(T));
        }
        public static T ElementOrDefault<T>(this T[] array, int index, T defaultValue)
        {
            return index < array.Length ? array[index] : defaultValue;
        }
    }
    

    然后代码如下:

    items.Zero = array[0];
    items.One = array[1];
    //...
    

    变成这样:

    items.Zero = array.ElementOrDefault(0);
    items.One = array.ElementOrDefault(1);
    //...
    

    最后,这是我开始编写此答案时使用的相当麻烦的想法:您可以将数组包装在保证具有 183 个索引的 IList 实现中(为简洁起见,我省略了大多数接口成员实现):

    class ConstantSizeReadOnlyArrayWrapper<T> : IList<T>
    {
        private readonly T[] _array;
        private readonly int _constantSize;
        private readonly T _padValue;
    
        public ConstantSizeReadOnlyArrayWrapper(T[] array, int constantSize, T padValue)
        {
             //parameter validation omitted for brevity
            _array = array;
            _constantSize = constantSize;
            _padValue = padValue;
        }
    
        private int MissingItemCount
        {
            get { return _constantSize - _array.Length; }
        }
    
        public IEnumerator<T> GetEnumerator()
        {
            //maybe you don't need to implement this, or maybe just returning _array.GetEnumerator() would suffice.
            return _array.Concat(Enumerable.Repeat(_padValue, MissingItemCount)).GetEnumerator();
        }
    
        public int Count
        {
            get { return _constantSize; }
        }
    
        public bool IsReadOnly
        {
            get { return true; }
        }
    
        public int IndexOf(T item)
        {
            var arrayIndex = Array.IndexOf(_array, item);
            if (arrayIndex < 0 && item.Equals(_padValue))
                return _array.Length;
            return arrayIndex;
        }
    
        public T this[int index]
        {
            get
            {
                if (index < 0 || index >= _constantSize)
                    throw new IndexOutOfRangeException();
                return index < _array.Length ? _array[index] : _padValue;
            }
            set { throw new NotSupportedException(); }
        }
    }
    

    确认。

    【讨论】:

      【解决方案3】:

      既然您已声明需要确保有 183 个索引,并且如果没有则需要填充它,我建议使用 List 而不是数组。您可以执行以下操作:

      while (extractList.Count < 183)
      {
           extractList.Add(" "); // just add a space
      }
      

      如果您绝对必须返回到数组,您可以使用类似的东西。

      【讨论】:

        【解决方案4】:

        Array 基类实现Resize 方法

        if(extractArray.Length < 183)
            Array.Resize<string>(ref extractArray, 183);
        

        但是,请记住,调整大小会影响性能,因此此方法仅在您出于某种原因需要数组时才有用。如果你可以切换到一个列表

        而且,我假设你这里有一个一维的字符串数组,所以我使用 Length 属性来检查数组中的有效项数。

        【讨论】:

          猜你喜欢
          • 2016-07-22
          • 2023-03-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-06-18
          • 2023-03-09
          • 2013-04-02
          • 1970-01-01
          相关资源
          最近更新 更多