Build array index ranges of an integer in C# .NET
February 16, 2017 Leave a comment
Suppose that we have a large array of data heavy objects that are impractical to handle in a single go. Instead we can read batches of the array until all elements have been processed. It can then be useful to build a range of indexes for the objects in the array that we want to extract.
E.g. if an array consists of 357 objects and we want to read at most 100 elements from it in a single batch then the size of the batches will be as follows:
100
100
100
57
…and we want to extract the elements by their indexes as follows:
0, 99
100, 199
200, 299
300, 356
…where the first number is the array start index and the second number is the array end index. Since we’re talking about array indexes the numbers are 0-based of course.
The first function we’ll need has been discussed in this post. It constructs the batch sizes as listed above 100, 100, 100 and 57:
private IEnumerable<int> BatchInteger(int total, int batchSize) { if (batchSize == 0) { yield return 0; } if (batchSize >= total) { yield return total; } else { int rest = total % batchSize; int divided = total / batchSize; if (rest > 0) { divided += 1; } for (int i = 0; i < divided; i++) { if (rest > 0 && i == divided - 1) { yield return rest; } else { yield return batchSize; } } } }
The start and end indexes could be stored in an object with two integer properties but for simplicity we can also return Tuples of two integers. The first integer will be the start index and the second integer will be the end index.
The following function will produce this range:
private List<Tuple<int, int>> GetArrayStartAndEndIndexes(int totalSize, int batchSize) { List<int> groups = BatchInteger(totalSize, batchSize).ToList(); List<Tuple<int, int>> arrayStartAndEndIndexes = new List<Tuple<int, int>>(); for (int i = 0; i < groups.Count; i++) { if (i == 0) { arrayStartAndEndIndexes.Add(new Tuple<int, int>(0, groups[i] - 1)); } else if (i == groups.Count - 1) { arrayStartAndEndIndexes.Add(new Tuple<int, int>(groups[i - 1] + ((i - 1) * batchSize), totalSize - 1)); } else { arrayStartAndEndIndexes.Add(new Tuple<int, int>(groups[i - 1] + ((i - 1) * batchSize), groups[i - 1] + (i * batchSize) - 1)); } } return arrayStartAndEndIndexes; }
It accepts a total size and a batch. In our example they will be 357 and 100. The function first calls BatchInteger to build the range sizes. For each item in the “groups” integer list we build an element for the Tuple. The first element will always have 0 as the start index and group size – 1 as the end index. All the decrements by one you see in the function are due to array indexing.
Usage:
var startAndEndIndexesOfArray = this.GetArrayStartAndEndIndexes(357, 100); foreach (var range in startAndEndIndexesOfArray) { Console.WriteLine(string.Concat("Start: ", range.Item1, ", end: ", range.Item2)); }
Here’s the printout:
Start: 0, end: 99
Start: 100, end: 199
Start: 200, end: 299
Start: 300, end: 356
Another function that processes the large array can use these index numbers to extract the necessary subarrays.
View all various C# language feature related posts here.