I have a function that I am passing a range of values, what is the best way to retrieve the values using the ExcelReference
public static object TestRange([ExcelArgument(AllowReference = true)]
object valueRange)
{
ExcelReference valueRangeRef = (ExcelReference)valueRange;
int rowFirst = valueRangeRef.RowFirst;
int rowLast = valueRangeRef.RowLast;
int colFirst = valueRangeRef.ColumnFirst;
int colLast = valueRangeRef.ColumnLast;
for (int i = colFirst; i < colLast; i++)
{
for (int j = rowFirst; j < rowFirst; j++)
{
//var value = ??
}
}
return "Done";
}
The easiest way to get the values is to mark your parameter as AllowReference=false - then you'll get an object[,] array with the values directly.
You can iterate through the values like this:
public static object Concat2(object[,] values)
{
string result = "";
int rows = values.GetLength(0);
int cols = values.GetLength(1);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
object value = values[i, j];
result += value.ToString();
}
}
return result;
}
If you do need to work with an ExcelReference, you can get the contents with a call to GetValue() which returns the same object[,].
Here's my code
public int[,] GetBigEyeRoad(int x)
{
int[,] arrayBigEyeResult = new int[6, x];
Array.Copy(arrayBigEyeRoad, arrayBigEyeResult, arrayBigEyeRoad.GetLength(0) * arrayBigEyeRoad.GetLength(1));
return arrayBigEyeResult;
}
And calling it on my main class like this
int[,] arrayBigEyeRoad = bsb.GetBigEyeRoad(104);
string s = "";
for (int y = 0; y < arrayBigEyeRoad.GetLength(0); y++)
{
for (int x = 0; x < arrayBigEyeRoad.GetLength(1); x++)
{
s += string.Format("{0:D2}", arrayBigEyeRoad[y, x]);
s += ".";
}
s += "\n";
}
Debug.Log(s);
Here on this part
int[,] arrayBigEyeRoad = bsb.GetBigEyeRoad(104);
I only want to display 12 2D array values just like this
int[,] arrayBigEyeRoad = bsb.GetBigEyeRoad(12);
The problem is that it won't let me . Because it will give me an error saying
Destination array was not long enough. Check destIndex and length, and the array's lower bounds
Now how can I possible do it something like this
Limit the 2d display on the console
Pretty simple:
int[,] a1 = new int[100,200];
int[,] a2 = new int[10,5];
for (int i = 0; i < 10; i++)
for (int j = 0; j < 5; j++)
a2[i,j] = a1[i,j];
or
public class MyArray : int[,]
{
public override string ToString()
{
string result = "";
for (int i = 0; i < 10; i++)
for (int j = 0; j < 5; j++)
result += (a1[i,j].ToString() + ",");
return result;
}
}
This is a simplified version of the problem im trying to solve. Im trying to add an int[] to a List, but it updates all the arrays in the List with the one from the last iteration. Why is that? And how does I solve this problem? This isn't a problem if it's just 1 int for example.
intArray = new int[9];
for (int i = 0; i < 9; i++)
{
intArray[i] = i;
}
Test.Add(intArray);
for (int i = 0; i < 9; i++)
{
intArray[i] = i * 2;
}
Test.Add(intArray);
foreach (var item in Test)
{
for (int i = 0; i < 9; i++)
{
Console.WriteLine(item[i]);
}
}
Console.ReadKey();
}
public static int[] intArray { get; set; }
public static List<int[]> Test = new List<int[]>();
Using new keyword you create intArray only once. Then there is only one reference. After that you add intArray reference to collection List for multiple times.
Try this,
intArray = new int[9];
for (int i = 0; i < 9; i++)
{
intArray[i] = i;
}
Test.Add(intArray);
intArray = new int[9]; // create new intArray here
for (int i = 0; i < 9; i++)
{
intArray[i] = i * 2;
}
Test.Add(intArray);
after u added your intArray object into your arraylist ,simply create another object of that
intArray = new int[length];
hope it will works
I have a string array defined in c# as
string[,] options = new string[100,3];
Throughout the code it gets populated with data but not always filled.
So if I have 80 parts of it filled and 20 parts of it not filled. The 20 parts have nulls in them or 60 nulls at the end. Is there an easy way to resize the array so that after filling it the array is the same as
String[,] options = new string[80,3];
It would have to be resized based on the position of the first set of 3 nulls it found.
If this was a jagged array I would have done
options = options.Where(x => x != null).ToArray();
The method is quite long, because it has to check every row twice...
public static string[,] RemoveEmptyRows(string[,] strs)
{
int length1 = strs.GetLength(0);
int length2 = strs.GetLength(1);
// First we count the non-emtpy rows
int nonEmpty = 0;
for (int i = 0; i < length1; i++)
{
for (int j = 0; j < length2; j++)
{
if (strs[i, j] != null)
{
nonEmpty++;
break;
}
}
}
// Then we create an array of the right size
string[,] strs2 = new string[nonEmpty, length2];
for (int i1 = 0, i2 = 0; i2 < nonEmpty; i1++)
{
for (int j = 0; j < length2; j++)
{
if (strs[i1, j] != null)
{
// If the i1 row is not empty, we copy it
for (int k = 0; k < length2; k++)
{
strs2[i2, k] = strs[i1, k];
}
i2++;
break;
}
}
}
return strs2;
}
Use it like:
string[,] options = new string[100, 3];
options[1, 0] = "Foo";
options[3, 1] = "Bar";
options[90, 2] = "fiz";
options = RemoveEmptyRows(options);
As suggested by Alexei, there is another way of doing this:
public static string[,] RemoveEmptyRows2(string[,] strs)
{
int length1 = strs.GetLength(0);
int length2 = strs.GetLength(1);
// First we put somewhere a list of the indexes of the non-emtpy rows
var nonEmpty = new List<int>();
for (int i = 0; i < length1; i++)
{
for (int j = 0; j < length2; j++)
{
if (strs[i, j] != null)
{
nonEmpty.Add(i);
break;
}
}
}
// Then we create an array of the right size
string[,] strs2 = new string[nonEmpty.Count, length2];
// And we copy the rows from strs to strs2, using the nonEmpty
// list of indexes
for (int i1 = 0; i1 < nonEmpty.Count; i1++)
{
int i2 = nonEmpty[i1];
for (int j = 0; j < length2; j++)
{
strs2[i1, j] = strs[i2, j];
}
}
return strs2;
}
This one, in the tradeoff memory vs time, chooses time. It is probably faster, because it doesn't have to check every row twice, but it uses more memory, because it puts somewhere a list of the non-empty indexes.
I went for all rows until you find an row with all null values:
Needs some clean up and will obviously remove non-null rows that occur after the first all null row. The requirement wasn't too clear here
EDIT: Just seen the comment clarifying requirement to remove all null rows - I've tweaked the below to avoid downvotes but a more comprehensive answer is already accepted (and is more efficient) :)
void Main()
{
string[,] options = new string[100,3];
options[0,0] = "bleb";
options[1,1] = "bleb";
options[2,0] = "bleb";
options[2,1] = "bleb";
options[3,2] = "bleb";
options[4,1] = "bleb";
string[,] trimmed = TrimNullRows(options);
Console.WriteLine(trimmed);
}
public string[,] TrimNullRows(string[,] options)
{
IList<string[]> nonNullRows = new List<string[]>();
for (int x = 0; x < options.GetLength(0); x++)
{
bool allNull = true;
var row = new string[options.GetLength(1)];
for (int y = 0; y < options.GetLength(1); y++)
{
row[y] = options[x,y];
allNull &= options[x,y] == null;
}
if (!allNull)
{
nonNullRows.Add(row);
}
}
var optionsTrimmed = new string[nonNullRows.Count, options.GetLength(1)];
for (int i=0;i<nonNullRows.Count;i++)
{
for (int j=0;j<options.GetLength(1);j++)
{
optionsTrimmed[i, j] = nonNullRows[i][j];
}
}
return optionsTrimmed;
}
You can also get yourself some helpers to convert between jagged and multi-dimensional representations. This is pretty silly, of course, but for arrays as small as the ones you're showing (and also, very sparse arrays), it'll be fine.
void Main()
{
string[,] options = new string[100,3];
options[3, 1] = "Hi";
options[5, 0] = "Dan";
var results =
options
.JagIt()
.Where(i => i.Any(j => j != null))
.UnjagIt();
results.Dump();
}
static class Extensions
{
public static IEnumerable<IEnumerable<T>> JagIt<T>(this T[,] array)
{
for (var i = 0; i < array.GetLength(0); i++)
yield return GetRow(array, i);
}
public static IEnumerable<T> GetRow<T>(this T[,] array, int rowIndex)
{
for (var j = 0; j < array.GetLength(1); j++)
yield return array[rowIndex, j];
}
public static T[,] UnjagIt<T>(this IEnumerable<IEnumerable<T>> jagged)
{
var rows = jagged.Count();
if (rows == 0) return new T[0, 0];
var columns = jagged.Max(i => i.Count());
var array = new T[rows, columns];
var row = 0;
var column = 0;
foreach (var r in jagged)
{
column = 0;
foreach (var c in r)
{
array[row, column++] = c;
}
row++;
}
return array;
}
}
The JagIt method is pretty simple of course - we'll just iterate over the rows, and yield the individual items. This gives us an enumerable of enumerables, which we can use in LINQ quite easily. If desired, you could transform those into arrays, of course (say, Select(i => i.ToArray()).ToArray()).
The UnjagIt method is a bit more talkative, because we need to create the target array with the correct dimensions first. And there's no unyield instruction to simplify that :D
This is pretty inefficient, of course, but that isn't necessarily a problem. You could save yourself some of the iterations by keeping the inner enumerable an array, for example - that will save us having to iterate over all the inner items.
I'm mostly keeping this as the memory-cheap, CPU-intensive alternative to #xanatos' memory-intensive, CPU-cheap (relatively).
Of course, the main bonus is that it can be used to treat any multi-dimensional arrays as jagged arrays, and convert them back again. General solutions usually aren't the most efficient :D
Yet another variant with linq
static string[,] RemoveNotNullRow(string[,] o)
{
var rowLen = o.GetLength(1);
var notNullRowIndex = (from oo in o.Cast<string>().Select((x, idx) => new { idx, x })
group oo.x by oo.idx / rowLen into g
where g.Any(f => f != null)
select g.Key).ToArray();
var res = new string[notNullRowIndex.Length, rowLen];
for (int i = 0; i < notNullRowIndex.Length; i++)
{
Array.Copy(o, notNullRowIndex[i] * rowLen, res, i * rowLen, rowLen);
}
return res;
}
string[][] myArray = new[size][];
for(int i=0;i<2;i++){
myArray[i][0] = newValue.toString();
}
While assigning the values i get an error
I get the Object Reference not set to instance of object exception. Please help
You have created a jagged array of strings. The outermost array has been initialized to size elements, but that means there are size spaces each for a string[], each of which is currently null. You need to create the inner arrays, or create a rectangular array.
Based on the poor code, it should be something like this:
string[][] myArray = new string[size][];
for (int j = 0; j < myArray.Length; j++) {
myArray[j] = new string[3];
for (int i = 0; i < myArray[j].Length; i++) {
myArray[j][i] = newValue.ToString();
}
}
Try this
int dim1 = 2;
int dim2 = 1;
string[,] iii = new string[dim1, dim2];
for (int i = 0; i < iii.GetLength(0); i++)
{
iii[i, 0] = "myValue";
}