1

I have a method that accepts an IEnumerable as a parameter. My issue is that this method is sometimes given an array that starts at 1 (instead of 0).

I could just create a list and add the elements of the parameter to it but isn't there a way of just getting the first index?

EDIT 1: What I mean with "an array that starts at 1" is an array that literally starts at 1, for example: enter image description here

I cannot access the array "cells" with the line:

cells[0, 0]

This specific array is being read from an Excel range.

EDIT 2: This isn't the only array that is being given to The method. The method also receives arrays that start at 0 and it needs to work for all cases.

juharr
  • 31,741
  • 4
  • 58
  • 93

5 Answers5

2

I don't understand what do you mean by .

sometimes given an array that starts at 1

The arrays must start at the zero index, I think you mean to try to filter the values and check if null empty values you can try the below:

var firstValue = array.First(x => !string.IsNullOrWhiteSpace(x.value));

Or you can remove the first element or any element on a condition

array = array.Skip(0);

UPDATE

When you pass a sub-array to the method, usually it doesn't start at index zero.

So, you can loop on the array to and handle the items after checking if it exists or not using ElementAtOrDefault() Linq method.

for (int i = 0; i < array.length; i++)
 {
    if(ElementAtOrDefault(i) != null)
        // your logic
 }
Shrembo
  • 833
  • 1
  • 8
  • 27
  • Arrays in .NET can have lower bounds that are not 0. – Martin Liversage Dec 22 '19 at 13:04
  • Okay, I got your point, this case usually happens when you pass a sub array to the method. – Shrembo Dec 22 '19 at 13:08
  • My comment is about your statement: _The arrays must start at the **zero index**_. This is not true in .NET. You can create arrays with a lower bound that is not 0. If the lower bound is 1 then you access the first element in the array using `array[1]`, not `array[0]`. – Martin Liversage Dec 22 '19 at 20:45
  • @MartinLiversage yeah, I got your point and I did add a new update to the answer and you can check if the element exists or not using `ElementAtOrDefault` – Shrembo Dec 23 '19 at 12:31
2

Normally arrays have a lower bound of 0. However, you can create arrays with different lower bounds. To do that you need to use Array.CreateInstance:

var array = Array.CreateInstance(typeof(string), new[] { 10 }, new[] { 1 });

This will create an one dimensional array with ten elements with a lower bound of 1. Here is how you set the value of the first element:

array.SetValue("first", 1);

In your case you could use code like this to create a two dimensional array with 10 x 20 elements and lower bounds of 1:

var array = (object[,]) Array.CreateInstance(typeof(object), new[] { 10, 20 }, new[] { 1, 1 });

And to get the lower bound of the first dimension you can use GetLowerBound:

var lowerBound = array.GetLowerBound(0);

Specify 1 as the argument to get the lower bound of the second dimension etc. There is also a GetUpperBound method. And in case you don't even know the dimensions of the array you can inspect the Rank property.

I believe this feature mostly exist to support porting old Visual Basic code to Visual Basic .NET and interop with COM automation (e.g. Excel) where arrays often have a lower bound of 1.

Martin Liversage
  • 104,481
  • 22
  • 209
  • 256
1

Depending on the need you can use each. Read the link below .

 var firstValue = Yourlist.First(x => x.value);

or

var firstValue = Yourlist.FirstOrDefault(x => x.value);

or

var firstValue = Yourlist.Single(x => x.value);

or

var firstValue = Yourlist.SingleOrDefault(x => x.value);

LINQ Single vs First

Amin Golmahalleh
  • 3,585
  • 2
  • 23
  • 36
  • `First` and `Single` take a `Func` predicate to filter on like `Where`, not a `Func` selector like `Select`. – juharr Dec 22 '19 at 14:27
  • @juharr My answer was before the question was changed. The questioner edited the question text. – Amin Golmahalleh Dec 22 '19 at 14:36
  • The change in the question has nothing to do with the fact that this code is incorrect unless `value` is of type `bool`. – juharr Dec 22 '19 at 14:44
1

As @MartinLiversage pointed out, there is an overload of Array.CreateInstance allowing to specify a lower bound:

public static Array CreateInstance (Type elementType, int[] lengths, int[] lowerBounds);

You have to cast the unspecific Array to a concrete type, to able to access its elements directly. Example:

var cells =
    (int[,])Array.CreateInstance(typeof(int), new[] { ROWS, COLUMNS }, new[] { 1, 1 }); 

You can get the bounds with cells.GetLowerBound(0) (first dimension) and cells.GetLowerBound(1) (second dimension). There is a corresponding GetUpperBound method. Example:

// Loop through the matrix
for (int i = cells.GetLowerBound(0); i <= cells.GetUpperBound(0); i++) {
    for (int j = cells.GetLowerBound(1); j <= cells.GetUpperBound(1); j++) {
        // Get an element
        var element = cells[i, j];

        // Set an element
        cells[i, j] = value;
    }
}

Or, to get the first element only:

var result = cells[cells.GetLowerBound(0), cells.GetLowerBound(1)];

You can also enumerate the array with foreach. This flattens the array, i.e. it treats the array as if it was one-dimensional.

Note, the LINQ extension method First always returns the first item, irrespective of the lower bounds of the array.

var result = cells.First();
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
0

If you are asking about Excel Interop:

  • Indexer - Indexer is 1-base:

    cells[1,1].Value2 = "something";
    
  • IEnumerable - Using Cast and First or FirstOrDefalt:

    cells.Cast<dynamic>().FirstOrDefault().Value2 = "something";
    
  • IEnumerable - Using GetEnumerator:

    var enumerator  = cells.GetEnumerator();
    enumerator.MoveNext();
    ((dynamic)enumerator.Current).Value2 = "something";
    
  • If you are interested to know about the column index and row index in the sheet, the Column and Row property will show the coordinates in the sheet.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398