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[,].
Related
I'm working on a class project and here is what I have so far. I know the code returns true when it finds a match but I want it to keep looping until no more instances are found.
I've looked at numerous sites on for/while loops but I can't seem to get the syntax correct and/or it doesn't work when applying the logic.
public bool Remove(T toRemove)
{
for (int i = 0; i < count; i++)
{
if (items[i].Equals(toRemove))
{
int removeIndex = i;
for (int j = removeIndex; j < count - 1; j++)
{
items[j] = items[j + 1];
}
return true;
}
}
return false;
}
If you want to complete the loop, do not return. Instead hold the result on a var you should return at the end:
public bool Remove(T toRemove)
{
bool result = false;
for (int i = 0; i < count; i++)
{
if (items[i].Equals(toRemove))
{
int removeIndex = i;
for (int j = removeIndex; j < count - 1; j++)
{
items[j] = items[j + 1];
}
result = true;
}
}
return result;
}
Just save the result in a variable and return it after the loop is complete:
public bool Remove(T toRemove)
{
bool result = false;
for (int i = 0; i < count; i++)
{
if (items[i].Equals(toRemove))
{
int removeIndex = i;
for (int j = removeIndex; j < count - 1; j++)
{
items[j] = items[j + 1];
}
result = true;
}
}
return result;
}
//Use a boolean variable and set it to true if an item is found,
//and continue your loop until you go through all elements, then return the boolean value.
public bool Remove(T toRemove)
{
bool match= false; //boolean to track if any match is found
for (int i = 0; i < count; i++)
{
if (items[i].Equals(toRemove))
{
int removeIndex = i;
for (int j = removeIndex; j < count - 1; j++)
{
items[j] = items[j + 1];
}
match= true;
}
}
return match;
}
I think what you want to do is declare a bool called "result" and instantiate it to false. In the loop where you are returning true, set "result" to true. At the end, where you are returning false, return "result"
I have a method which returns the following type and object:
object {object[,]}
test {object[19, 2]}
Is it possible to convert this into 2d string array, or a datatable?
Looks akward, but I haven't found another way.
int firstDimensionSize = 19;
int secondDimensionSize = 2;
object[,] objectArray = new object[firstDimensionSize, secondDimensionSize];
string[,] stringArray = new string[objectArray.Length / secondDimensionSize, secondDimensionSize];
for (int i = 0; i < objectArray.Length / secondDimensionSize; i++)
{
for (int j = 0; j < secondDimensionSize; j++)
{
stringArray[i, j] = objectArray[i, j].ToString();
}
}
In case your second dimension is always the same you could leave out the inner loop, replacing it with static code.
See also https://www.dotnetperls.com/2d
I made this extension method, but you can aswell make it a normal method if you don't need it that often.
public static class Extensions
{
public static string[,] ConvertToString2D(this object[,] arr)
{
int dim1 = arr.GetLength(0);
int dim2 = arr.GetLength(1);
string[,] strArray = new string[dim1, dim2];
for (int i = 0; i < dim1; i++)
{
for (int j = 0; j < dim2; j++)
{
strArray[i, j] = Convert.ToString(arr[i, j]);
}
}
return strArray;
}
}
and then you can call it like this:
var result = objArr.ConvertToString2D();
I have written the following code but it looks to be far from efficient.
//Find largest in tempRankingData
int largestIntempRankingData = tempRankingData[0, 0];
for (int i = 0; i < count; i++)
{
for (int j = 0; j < count; j++)
{
if (tempRankingData[i, j] > largestIntempRankingData)
{
largestIntempRankingData = tempRankingData[i, j];
}
}
}
//Find position of largest in tempRankingData
List<string> positionLargestIntempRankingData = new List<string>();
for (int i = 0; i < count; i++)
{
for (int j = 0; j < count; j++)
{
if (tempRankingData[i, j] == largestIntempRankingData)
{
positionLargestIntempRankingData.Add(i + "," + j);
}
}
}
//Find largest in each column
int largestInColumn = 0;
List<string> positionOfLargestInColumn = new List<string>();
Dictionary<int, List<string>> position = new Dictionary<int, List<string>>();
for (int i = 0; i < count; i++)
{
largestInColumn = tempRankingData[0, i];
positionOfLargestInColumn = new List<string>();
for (int j = 0; j < count; j++)
{
if (tempRankingData[j, i] > largestInColumn)
{
largestInColumn = tempRankingData[j, i];
}
}
for (int j = 0; j < count; j++)
{
if (tempRankingData[j, i] == largestInColumn)
{
positionOfLargestInColumn.Add(j + "," + i);
}
}
position.Add(i, positionOfLargestInColumn);
}
So, I wanted to check about the most efficient way to do this.
Whilst you're finding the largest in each column, you could also be finding the largest overall. You can also capture the positions as you go:
//Find largest in each column
int largestInColumn = 0;
int largestOverall = int.MinValue;
List<string> positionOfLargestInColumn;
Dictionary<int, List<string>> position = new Dictionary<int, List<string>>();
List<string> positionLargestIntempRankingData = new List<string>();
for (int i = 0; i < count; i++)
{
largestInColumn = tempRankingData[0, i];
positionOfLargestInColumn = new List<string>();
positionOfLargestInColumn.Add("0," + i);
for (int j = 1; j < count; j++)
{
if (tempRankingData[j, i] > largestInColumn)
{
largestInColumn = tempRankingData[j, i];
positionOfLargestInColumn.Clear();
positionOfLargestInColumn.Add(j + "," + i);
}
else if(tempTankingData[j,i] == largestInColumn)
{
positionOfLargestInColumn.Add(j + "," + i);
}
}
position.Add(i, positionOfLargestInColumn);
if(largestInColumn > largestOverall)
{
positionLargestIntempRankingData.Clear();
positionLargestIntempRankingData.AddRange(positionOfLargestInColumn);
largestOverall = largestInColumn;
}
else if(largestInColumn == largestOverall)
{
positionLargestIntempRankingData.AddRange(positionOfLargestInColumn);
}
}
1). You can find largest element and its position in one method and retrieve.
Would be caller of your method concerned about position or actual value, is a matter of concrete case.
2) You can use `yield return' technique in your matrix search (for column based search), so do not compute all column's maximas and push them into the dictionary. Dictionaries are not that fast as arrays, if you can avoid use them, do that.
3) You can keep a matrix in single dimension, long array. Have [] access operator overload, to "emulate" matrix access. Why ? If finding maximum is something frequent you might need to do during program run, having one foreach loop is faster then having 2 nested once. In case of a big matrices, single array search can be easily parallelized among different cores.
If big matrices and/or frequent calls are not your concern, just simplify your code like in points (1), (2).
For your fist two itterations you could replace with this:
//Find largest in tempRankingData
int largestIntempRankingData = tempRankingData[0, 0];
List<KeyValuePair<double,string>> list = new List<KeyValuePair<double,string>>();
for (int i = 0; i < count; i++)
{
for (int j = 0; j < count; j++)
{
if (tempRankingData[i, j] > largestIntempRankingData)
{
largestIntempRankingData = tempRankingData[i, j];
list.Add(new KeyValuePair<double, string>(largestIntempRankingData, i + "," + j)); //Add the value and the position;
}
}
}
//This gives a list of strings in which hold the position of largestInItemRankingData example "3,3"
//Only positions where the key is equal to the largestIntempRankingData;
list.Where(w => w.Key == largestIntempRankingData).ToList().Select(s => s.Value).ToList();
You can get all these pieces of information in a single scan with a little fiddling around. Something like this (converting the rows and columns to a string is trivial and better done at the end anyway):
int? largestSoFar = null; // you could populate this with myMatrix[0,0]
// but it would fail if the matrix is empty
int largestCol = 0;
int largestRow = 0;
int?[] largestPerColumn = new int?[numOfCols]; // You could also populate this with
// the values from the first row but
// it would fail if there are no rows
int[] largestColumnRow = new int[numOfCols];
for (int i = 0; i < numOfRows; i++)
{
for (int j = 0; j < numOfCols; i++)
{
if (largestSoFar < myMatrix[i,j])
{
largestSoFar = myMatrix[i,j];
largestCol = j;
largestRow = i;
}
if (largestPerColumn[j] < myMatrix[i,j])
{
largestPerColumn[j] = myMatix[i,j];
largestColumnRow[j] = i;
}
}
}
// largestSoFar is the biggest value in the whole matrix
// largestCol and largestRow is the column and row of the largest value in the matrix
// largestPerColumn[j] is the largest value in the jth column
// largestColumnRow[j] is the row of the largest value of the jth column
If you do need to capture all the "maxima" (for want of a better word, because that's not really what you are doing) in a column, you could just change the above code to something like this:
int? largestSoFar = null; // you could populate this with myMatrix[0,0]
// but it would fail if the matrix is empty
int largestCol = 0;
int largestRow = 0;
int?[] largestPerColumn = new int?[numOfCols]; // You could also populate this with
// the values from the first row but
// it would fail if there are no rows
List<int>[] largestColumnRow = new List<int>[numOfCols];
for (int i = 0; i < numOfRows; i++)
{
for (int j = 0; j < numOfCols; i++)
{
if (largestSoFar < myMatrix[i,j])
{
largestSoFar = myMatrix[i,j];
largestCol = j;
largestRow = i;
}
if (largestPerColumn[j] < myMatrix[i,j])
{
largestPerColumn[j] = myMatix[i,j];
largestColumnRow[j].Add(i);
}
}
}
// Now largestColumnRow[j] gives you a list of all the places where you found a larger
// value for the jth column
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;
}
im trying to create a 3x3 matrix in c# language, i know how to create the matrix but i need help for user input numbers. I hope someone can help me thank you for that.
I will add a while loop and use double.TryParse to validate user's input. Usin BWHazel's code:
const int MATRIX_ROWS = 3;
const int MATRIX_COLUMNS = 3;
double[,] matrix = new double[MATRIX_ROWS, MATRIX_COLUMNS];
for (int i = 0; i < MATRIX_ROWS; i++)
{
for (int j = 0; j < MATRIX_COLUMNS; j++)
{
double input;
Console.Write("Enter value for ({0},{1}): ", i, j);
while (!double.TryParse(Console.ReadLine(), out input)
{
Console.Write("Enter correct value for ({0},{1}): ", i, j);
}
matrix[i,j] = input
}
}
To get the totals for all rows you can use following snippet:
for (int i = 0; i < MATRIX_ROWS; i++)
{
// The some for each row
double sum = 0.0;
for (int j = 0; j < MATRIX_COLUMNS; j++)
{
sum += matrix[i,j];
}
Console.WriteLine(string.format("The sum for row {0} is: {1}", i, sum));
}
If you are using the command-line, something like this should work:
const int MATRIX_ROWS = 3;
const int MATRIX_COLUMNS = 3;
double[,] matrix = new double[MATRIX_ROWS, MATRIX_COLUMNS];
for (int i = 0; i < MATRIX_ROWS; i++)
{
for (int j = 0; j < MATRIX_COLUMNS; j++)
{
Console.Write("Enter value for ({0},{1}): ", i, j);
matrix[i,j] = double.Parse(Console.ReadLine());
}
}
This assumes you are using double for the values. The .Parse() method is available for all .NET numeric types including int.
private void button1_Click(object sender, EventArgs e)
{
txtResult.Text=GenerateMatrix(Int32.Parse(txtRow.Text), Int32.Parse(txtColumn.Text));
}
private string GenerateMatrix(int Row,int Column)
{
string matrix = string.Empty;
string Result = string.Empty;
int nxtline=0;
for (int i = 0; i < Row; i++)
{
for (int j = 0; j < Column; j++)
{
if (nxtline==Column)
{
matrix = matrix + Environment.NewLine;
nxtline = 0;
}
matrix = matrix+"*";
nxtline = nxtline + 1;
}
}
Result = matrix;
return Result;
}