8

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.

Chris Laplante
  • 29,338
  • 17
  • 103
  • 134
Kobojunkie
  • 6,375
  • 31
  • 109
  • 164
  • 7
    Have you thought about just using the `List` instead of an array? – PiousVenom Oct 03 '12 at 21:08
  • 2
    How are you processing it so that you get a index out of bounds error? Will a `foreach` not work in this case? – Dave Zych Oct 03 '12 at 21:09
  • @Prayos i would upvote your comment 10 more times but the system won't let me. Kobojunkie, why do you want to use an array *per se* ? – Thousand Oct 03 '12 at 21:09
  • This does seem kinda funny, given the great collection types that we get in the .NET API. I am assuming though that you are passing an array to a 'for' loop that goes 183 times? You do not have control over this code? – iMortalitySX Oct 03 '12 at 21:15
  • I am not passing it through a for loop. I am simply assigning each of the 183 items in the resulting array to specific items in my code. – Kobojunkie Oct 03 '12 at 21:21
  • I chose to use an array in this case since I don't really need extra bells and whistles but just the basic accessing of indexed data from my extract. If you think this is not a good idea, do let me know your collection of choice and why it is necessarily better than the array for this. – Kobojunkie Oct 03 '12 at 21:25
  • @Kobojunkie: I would go with a `List<>` for this simply because there would be zero need for this padding stuff. It's better than an array because it can dynamically change to be whatever size it needs to be. – PiousVenom Oct 03 '12 at 21:28
  • 1
    We don't know the cause of the OP requirement for a 183 items array. Switching to a `List<>` will not answer to this requirement, whatever it is. – Steve Oct 03 '12 at 21:35
  • Yes, I don't think switching over to a list will solve this either since I also have to ensure I have the 183 indexes in my list to access. – Kobojunkie Oct 03 '12 at 21:37
  • @Kobojunkie: You can do a `if(list.Count == 183)` check to ensure there's 183. But I got to ask, why 183 specifically? And if it HAS to have 183 indexes, you can easily pad a List with something like a do loop, `do {list.add(" ")} until(list.Count == 183)`. – PiousVenom Oct 03 '12 at 21:39
  • There are 183 records I expect to extract from my file. – Kobojunkie Oct 03 '12 at 21:41

4 Answers4

8

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.

phoog
  • 42,068
  • 6
  • 79
  • 117
6

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.

Steve
  • 213,761
  • 22
  • 232
  • 286
2

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.

PiousVenom
  • 6,888
  • 11
  • 47
  • 86
2

I can't say that I would recommend this solution, but I won't let that stop me from posting it! Whether they like to admit it or not, everyone likes linq solutions!

Using linq, given an array with X elements in it, you can generate an array with exactly Y (183 in your case) elements in it like this:

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

If there are fewer than 183 elements, the array will be padded with empty strings. If there are more than 183 elements, the array will be truncated. If there are exactly 183 elements, the array is used as is.

I don't claim that this is efficient or that it is necessarily a good idea. However, it does use linq (yippee!) and it is fun.

wageoghe
  • 27,390
  • 13
  • 88
  • 116