Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Way to pad an array to avoid index outside of bounds of array error

I expect to have at least 183 items in my list when I query it, but sometimes the result from my extract results in items count lower than 183. My current fix supposedly pads the array in the case that the count is less than 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
}

But it seems my solution is not the best. I would appreciate any other solutions that could help ensure I get at least 183 items whenever the extract happens please.

like image 288
Kobojunkie Avatar asked Oct 03 '12 21:10

Kobojunkie


Video Answer


3 Answers

I'd probably follow others' suggestions, and use a list. Use the "capacity" constructor for added performance:

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

Then, whenever you get a new array, do this (replace " " with whatever value you use to pad the array):

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

This way, the list is always reusing the same internal array, reducing allocations and GC pressure.

Or, you could use an extension method:

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

Then code like this:

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

Becomes this:

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

Finally, this is the rather cumbersome idea with which I started writing this answer: You could wrap the array in an IList implementation that's guaranteed to have 183 indexes (I've omitted most of the interface member implementations for brevity):

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(); }
    }
}

Ack.

like image 66
phoog Avatar answered Sep 27 '22 20:09

phoog


The Array base class implements the Resize method

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

However, keep in mind that resizing is problematic for performance, thus this method is useful only if you require the array for some reason. If you can switch to a List

And, I suppose you have an unidimensional array of strings here, so I use the Length property to check the effective number of items in the array.

like image 25
Steve Avatar answered Sep 27 '22 21:09

Steve


Since you've stated that you need to ensure there's 183 indexes, and that you need to pad it if there is not, I would suggest using a List instead of an array. You can do something like:

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

If you ABSOLUTELY have to go back to an array you can using something similar.

like image 35
PiousVenom Avatar answered Sep 27 '22 20:09

PiousVenom