I am trying to create a 2D array from a DataTable, however Instead of getting the end result defined below. One row is not added, if that row is added, it will overwrite the column values.
Here is the end result I am looking to get:
[
//columns
['TaskID','TaskName','StartDate','EndDate','Duration','PercentComplete','Dependecies'],
//rows
['Cite','Create bibliography',null,1420649776903,1,20,'Research'], //missing row
['Complete','Hand in paper',null,1420908976903,1,0,'Cite,Write'],
['Outline','Outline paper',null,1420563376903,1,100,'Research'],
['Research','Find sources',1420390576903,1420476976903,null,100,null],
['Write','Write paper',null,1420822576903,3,25,'Research,Outline']
];
However, I get this.
[
["TaskID","TaskName","StartDate","EndDate","Duration","PercentComplete","Dependecies"],
["Complete","Hand in paper",null,1420908976903.0,1,0,"Cite,Write"],
["Outline","Outline paper",null,1420563376903.0,1,100,"Research"],
["Research","Find sources",1420390576903.0,1420476976903.0,null,100,null],
["Write","Write paper",null,1420822576903.0,3,25,"Research,Outline"]
]
I have tried:
// define the array size based on the datatable
object[,] multiDimensionalArry = new Object[breDataTable.Rows.Count, breDataTable.Columns.Count];
const int columnsArryIndex = 0;
// populate array with column names
if (breDataTable.Columns.Count > 0 && breDataTable.Rows.Count > 0)
{
// loop around columns
for (int i = 0; i <= breDataTable.Columns.Count - 1; i++)
{
// add all the column names
multiDimensionalArry[columnsArryIndex, i] = breDataTable.Columns[i].ColumnName;
}
}
// outer loop - loop backwards from the bottom to the top
// we want to exit the loop, when index == 0 as that is reserved for column names
for (int j = breDataTable.Rows.Count - 1; j >= 0; j--)
{
// get current row items array to loop through
var rowItem = breDataTable.Rows[j].ItemArray;
// inner loop - loop through current row items, and add to resulting multi dimensional array
for (int k = 0; k <= rowItem.Length - 1; k++)
{
multiDimensionalArry[j, k] = rowItem[k];
}
}
You're missing one row when creating your array since the columns name row dosent count as a row
object[,] multiDimensionalArry = new Object[breDataTable.Rows.Count + 1, breDataTable.Columns.Count];
And you need to change your for loop to take into count the extra row
// outer loop - loop backwards from the bottom to the top
// we want to exit the loop, when index == 0 as that is reserved for column names
for (int j = breDataTable.Rows.Count - 1; j >= 0; j--)
{
// get current row items array to loop through
var rowItem = breDataTable.Rows[j].ItemArray;
// inner loop - loop through current row items, and add to resulting multi dimensional array
for (int k = 0; k <= rowItem.Length - 1; k++)
{
multiDimensionalArry[j + 1, k] = rowItem[k];
}
}
Related
I have a program that I'm writing to extract certain data from various excel spreadsheet.
The process so far is:
for each spreadsheet identified:
-read in the data as a multidimensional array using interop excel (Even though it is slow, it is the best choice due to all of the different file formats I need to read in)
Sample: object[,] cellValues = (object[,])range.Value2;
-Identify the columns that I actually need and what order I need them in. This is stored in a jagged array of bytes:
byte[][] targetColumns
-THe jagged array essentially is (columnIndexFromSpreadsheet, preferredColumnOrder) e.g. if the first column in the spreadsheet should be read in as column 10 it would be (1, 10)
-I sort the jagged array by the preferred column order (that way I can just loop through the array in that order and extract those columns):
public static byte[][] SortTargetColumns(byte[][] targetColumns)
{
return targetColumns.OrderBy(x => x.Skip(1).First()).ToArray();
}
-I then extract that column by creating an array from that column index of the multidimensional array. This is the method that is called:
public static object[] ExtractColumn(object[,] dataArray ,byte columnIndex)
{
return Enumerable.Range(ArrayIndexStart, dataArray.GetLength(0)).Select(x => dataArray[x, columnIndex]).ToArray();
}
Usage:
array = ExtractColumn(dataArray, (byte) colIndex);
Now I am trying to piece these extracted arrays back together to make it readable. I will need to do some manipulation on some of the columns and then write to a text file after consolidating. The only problem is that I have no idea how to do this correctly. I have tried the following methods but continue to get a null reference exception:
// Get Row Count of dataArray
int rowCount = dataArray.GetLength(0);
// Create List to store extracted arrays
List<object[]> extractedDataList = new List<object[]>();
// Loop through target columns and extract the column as an array
for (byte colIndex = 1; colIndex <= targetColumns.Length + 1; colIndex++)
{
object[] array = ExtractColumn(dataArray, (byte) colIndex);
extractedDataList.Add(array);
}
// Create jagged array
object[][] extractedDataArray = new object[rowCount][] ;
for(int i = 0; i < extractedDataArray.GetLength(0); i++)
{
List<object> row = new List<object>();
for (int j = 0; j < extractedDataList.Count; j++)
{
row.Add(extractedDataList[j][i].ToString());
//extractedDataArray[i][j] = extractedDataList[j][i].ToString(); <-- null reference
}
extractedDataArray[i] = row.ToArray();
}
I'm at a loss of what else to try to put these column arrays back in a form that I can easily work with. Any and all tips/recommendations would be greatly appreciated.
Whenever you get confused like this, break the problem down into small pieces, and use meaningful names.
Let's say you have an array of columns, each of which has one element per row. That might be declared like this:
object[][] columns;
First, let's get the row and column counts:
var columnCount = columns.Length;
var rowCount = columns[0].Length;
Now write a small local function to accept a row and column index and return the right cell. In case not all of your columns have the same number of rows, you can include a boundary check and just return null if a cell isn't there.
object Getter(int row, int col)
{
bool outOfBounds = (row >= columns[col].Length);
return outOfBounds ? null : columns[col][row];
}
Now all we have to do is iterate over the rows to create the inner arrays:
object[][] target = new object[rowCount][]
for (int row = 0; row < rowCount; row++)
{
target[row] = new object[columnCount];
}
And add in the code that uses the getter to populate the cells:
object[][] target = new object[rowCount][];
for (int row = 0; row < rowCount; row++)
{
target[row] = new object[columnCount];
for (int col = 0; col < columnCount; col++)
{
var cellValue = Getter(row, col);
target[row][columnCount] = cellValue;
}
}
All together, it is simple to read:
var columnCount = columns.Length;
var rowCount = columns[0].Length;
object Getter(int row, int col)
{
bool outOfBounds = (row >= columns[col].Length);
return outOfBounds ? null : columns[col][row];
}
object[][] target = new object[rowCount][];
for (int row = 0; row < rowCount; row++)
{
target[row] = new object[columnCount];
for (int col = 0; col < columnCount; col++)
{
var cellValue = Getter(row, col);
target[row][columnCount] = cellValue;
}
}
dailyMenu [,] daysOfMonth = new dailyMenu[4,5];
for (int column = 0; column < daysOfMonth.Length; column++)
{
for (int row = 0; row < daysOfMonth.Length; row++)
{
dailyMenu dm = new dailyMenu ();
}
}
My question is I want to know how to fill my 2D array with new objects of my dailyMenu class?
For the 2-D array, you probably want to get the length by GetLength(0) and GetLength(1) instead of by using Length:
dailyMenu [,] daysOfMonth = new dailyMenu[4,5];
for (int column = 0; column < daysOfMonth.GetLength(0); column++)
{
for (int row = 0; row < daysOfMonth.GetLength(1); row++)
{
dailyMenu dm = new dailyMenu ();
//do something on dm
daysOfMonth[column,row] = dm; //assign it like this
}
}
This is because GetLength has argument of dimension index (0, 1, 2, etc...) Which can give you the length of the array in that dimension (0 being the first dimension - in your case column, and 1 being the second - in your case row. Length does not have that.
To assign a value to the array, simply access the array by the dimension indexes (column and row) in the correct order - otherwise you will get IndexOutOfRange exception:
daysOfMonth[column,row] = dm; //correct
daysOfMonth[row,column] = dm; //wrong, exception on 5,0
My question is I want to know how fill my 2D array with new objects of my dailyMenu class?
After initializing dm.
daysOfMonth[column,row] = dm
You can use .GetLength() to find out the length of a dimension. Alternatively just use the same constants you use in 2D array constructor.
dailyMenu [,] daysOfMonth = new dailyMenu[4,5];
for (int column = 0; column < daysOfMonth.GetLength(0); column++)
{
for (int row = 0; row < daysOfMonth.GetLength(1); row++)
{
daysOfMonth[column,row] = new dailyMenu ();
}
}
How can I sort a 2D array in C#
I have looked at other answers to this question but they don't do exactly what I need.
The array is variable height * 5 across
The array holds strings
I need the array sorted based on either column, for example sort in alphabetical the third column, however all other columns must be updated.
Does anyone know of a quick and easy solution?
My code is a mess, here is a shortened version:
string[,] tmp = new string[2, 3];//this is filled with strings
string y = Console.ReadLine();
int x = Convert.ToInt32(y);
// sort tmp based on x column
How do I sort a two-dimensional array in C#? contains a possible solution to this by reading your data into a datatable and then using the object's methods to sort:
// assumes stringdata[row, col] is your 2D string array
DataTable dt = new DataTable();
// assumes first row contains column names:
for (int col = 0; col < stringdata.GetLength(1); col++)
{
dt.Columns.Add(stringdata[0, col]);
}
// load data from string array to data table:
for (rowindex = 1; rowindex < stringdata.GetLength(0); rowindex++)
{
DataRow row = dt.NewRow();
for (int col = 0; col < stringdata.GetLength(1); col++)
{
row[col] = stringdata[rowindex, col];
}
dt.Rows.Add(row);
}
// sort by third column:
DataRow[] sortedrows = dt.Select("", "3");
// sort by column name, descending:
sortedrows = dt.Select("", "COLUMN3 DESC");
So first we'll want to convert the multi-dimensional array into a sequence of single-dimensional arrays representing the rows, so that each row can be manipulated as a unit:
public static IEnumerable<T[]> GetRows<T>(T[,] array)
{
for (int i = 0; i < array.GetLength(0); i++)
{
T[] row = new T[array.GetLength(1)];
for (int j = 0; j < row.Length; j++)
{
row[j] = array[i, j];
}
yield return row;
}
}
Then we'll also need a method that does the reverse to get a multi-dimensional array back when we're done:
public static T[,] ToMultiDimensionalArray<T>(T[][] rows)
{
T[,] output = new T[rows.Length, rows[0].Length];
for (int i = 0; i < rows.Length; i++)
for (int j = 0; j < rows[0].Length; j++)
{
output[i, j] = rows[i][j];
}
return output;
}
Now we just need to sort a sequence of arrays, and Linq makes this quite easy:
tmp = ToMultiDimensionalArray(GetRows(tmp)
.OrderBy(row => row[2]).ToArray());
I have a 2-dimensional array with user-entered values. I need to find sum of the even elements in the diagonal of the array.
I know how to declare the array and get it filled by the user, but I'm not sure what even elements in the main diagonal really means.
I know I can find out if a number is even by saying:
if n / 2 == 0
Once I've reported the sum of the even elements in the diagonal, I would like to replace all 0 values in the array with ones.
Diagonal means all places where x and y cordinates are the same
Do if your array contains:
1 3 8 5
3 3 9 7
4 4 5 7
5 1 7 4
Then the diagonal are in bold.
Assuming the array is a square:
int sum = 0;
for(int i = 0; i < numOfArrayRows; i++)
{
//Use the mod operator to find if the value is even.
if(array[i][i] % 2 == 0)
sum += array[i][i];
//Change 0's to ones
for(int j = 0; j < numOfArrayCols; j++)
if(array[i][j] == 0)
array[i][j] = 1;
}
Also, next time add the "Homework" tag if you have a homework question :P
With a two-dimensional array it's really easy, since you don't need any index magic:
int a[N][N] = ...;
int sum = 0;
for(int i=0; i<N; ++i)
if(a[i][i] % 2 == 0) //or a[i] & 1, if you like, just check if it's dividable by 2
sum += a[i][i];
This C++ code shouldn't be that different in C or C#, but you should get the point. Likewise the second question would be as simple as:
int a[M][N] = ...;
for(i=0; i<M; ++i)
for(j=0; j<N; ++j)
if(a[i][j] == 0)
a[i][j] = 1;
And I suspec that the main diagonal is the one that begins with coordinates 0,0.
To replace 0 elements with 1 you would do something like:
if (array[i,j] == 0) array[i,j] == 1;
This sounds like homework - however I will help out :)
So if you have an 2D array, and in order to find the sum of the diagonal values, you will know that the indices of both of the values would match in order to provide you with each of the diagonal values.
To iterate through these you could use a simple loop that would sum up every diagonal value, as shown:
//Your Sum
int sum = 0;
//This will iterate and grab all of the diagonals
//You don't need to iterate through every element as you only need
//the diagonals.
for(int i = 0; i < sizeOfArray; i++)
{
//This will add the value of the first, second, ... diagonal value to your sum
sum += array[i,i];
}
To set each of the values that is 0 to 1, you could iterate through each element of the array and check if the value is 0, then set that value to 1, for example:
for(int i = 0; i < sizeOfArray; i++)
{
for(int j = 0; j < sizeOfArray; j++)
{
//Check if this value is 0;
//If it is 0, set it to 1, otherwise continue
}
}
int[,] array = new int[,] {{1,2,3},
{4,5,6},
{7,8,9}};
//Suppose you want to find 2,5,8
for(int row = 0; row < 3; row++)
{
for(int column = 0; column < 3; column++)
{
if((row == 0 && column == 1) || (row == 1 && column == 1) || (row == 2 && column == 1))
{
Console.WriteLine("Row: {0} Column: {1} Value: {2}",row + 1, column + 1, array[row, column]);
}
}
}
Here is the code you need, not much explain:
//Read the size of the array, you can get it from .Count() if you wish
int n = Convert.ToInt32(Console.ReadLine());
int[][] a = new int[n][];
//Reading all the values and preparing the array (a)
for (int a_i = 0; a_i < n; a_i++)
{
string[] a_temp = Console.ReadLine().Split(' ');
a[a_i] = Array.ConvertAll(a_temp, Int32.Parse);
}
//performing the operation (google what diagonal matrix means)
int PrimarySum = 0, SecondarySum = 0;
for (int i = 0; i < n; i++)
{
//The If condition is to skip the odd numbers
if (a[i][i] % 2 == 0) { PrimarySum += a[i][i]; }
//For the reverse order
int lastelement = a[i].Count() - 1 - i;
if (a[i][lastelement] % 2 == 0) { SecondarySum += a[i][lastelement]; }
}
//Get the absolute value
Console.WriteLine(Math.Abs(PrimarySum - SecondarySum).ToString());
Console.ReadKey();
I am making a program that stores data in a 2D array. I would like to be able to delete rows from this array. I cannot figure out why this code doesn't work:
for (int n = index; n < a.GetUpperBound(1); ++n)
{
for (int i = 0; i < a.GetUpperBound(0); ++i)
{
a[i, n] = a[i, n + 1];
}
}
Could someone please help me out? I would like it to delete a single row and shuffle all the rows below it up one place. Thankyou!
you need to create a new array if you want to delete an item
try something like this
var arrayUpdated = new string[a.GetUpperBound(1)][a.GetUpperBound(0)-1];
for (int n = index; n < a.GetUpperBound(1); n++)
{
for (int i = 0; i < a.GetUpperBound(0); i++)
{
arrayUpdated [i, n] = a[i, 1];
}
}
The nested for loop method here works well: https://stackoverflow.com/a/8000574
Here's a method that converts the outer loop of the [,] array method above to use linq. Using linq here is only recommended if you are also doing other things with linq during the traversal.
public T[,] RemoveRow<T>(T[,] array2d, int rowToRemove)
{
var resultAsList = Enumerable
.Range(0, array2d.GetLength(0)) // select all the rows available
.Where(i => i != rowToRemove) // except for the one we don't want
.Select(i => // select the results as a string[]
{
T[] row = new T[array2d.GetLength(1)];
for (int column = 0; column < array2d.GetLength(1); column++)
{
row[column] = array2d[i, column];
}
return row;
}).ToList();
// convert List<string[]> to string[,].
return CreateRectangularArray(resultAsList); // CreateRectangularArray() can be copied from https://stackoverflow.com/a/9775057
}
used Enumerable.Range to iterate all rows as done in https://stackoverflow.com/a/18673845
Shouldn't ++i be i++? ++i increments before matrix operation is performed(ie pre-increment)