Copy 2D Array in C# - c#

I have a code that stored the data to a temporary array.
string filename = openFileDialog1.FileName;
string[] line = File.ReadAllLines(filename);
using (var reader2 = File.OpenText(#filename))
{
for (int i = 0; i < line.Length; i++)
{
string lines = reader2.ReadLine();
var data = lines.Split(',');
double[,] arrayTemp = new double[line.Length, 2];
arrayTemp[i, 0] = double.Parse(data[0]);
arrayTemp[i, 1] = double.Parse(data[1]);
}
Array.Copy(arrayTemp, GlobalDataClass.dDataArray, line.Length); //error the name "arrayTemp" does not exist in the current context.
}
Since 2d array is not resizable and I want my global array to be flexible,so I use the Array.Copy method to copy the temp array to the Global class array. However I got an error as commented in my code above.
My question is how to copy the tempArray to the global class array.
Any idea how to fix this?

Problem : You have declared your array variable arrayTemp inside the for loop and it is not available outside of it.
Solution : You need to move your array variable arrayTemp declaration outside the loop.
Try This:
string filename = openFileDialog1.FileName;
string[] line = File.ReadAllLines(filename);
double arrayTemp=new double[line.Length,2];//declare outside forloop so it available after forloop.
GlobalDataClass.dDataArray=new double[line.Length,2]; //add this line
using (var reader2 = File.OpenText(#filename))
{
for (int i = 0; i < line.Length; i++)
{
string lines = reader2.ReadLine();
var data = lines.Split(',');
GlobalDataClass.dDataArray[i, 0] = double.Parse(data[0]);
GlobalDataClass.dDataArray[i, 1] = double.Parse(data[1]);
}
Array.Copy(arrayTemp, GlobalDataClass.dDataArray, line.Length);
}

EDIT:
it seems that you are trying to copy the contents of arrayTemp to GlobalDataClass.dDataArray, but you are assigning values to GlobalDataClass.dDataArray, and trying to copy empty arrayTemp to GlobalDataClass.dDataArray.
So first declare the tempArray outside the for-loop and then populate it instead of GlobalDataClass.dDataArray inside the for-loop accordingly:
string filename = openFileDialog1.FileName;
string[] line = File.ReadAllLines(filename);
var arrayTemp = new double[line.Length, 2];
using (var reader2 = File.OpenText(#filename))
{
for (int i = 0; i < line.Length; i++)
{
string lines = reader2.ReadLine();
var data = lines.Split(',');
arrayTemp[i, 0] = double.Parse(data[0]);
arrayTemp[i, 1] = double.Parse(data[1]);
}
Array.Copy(arrayTemp, GlobalDataClass.dDataArray, line.Length); // now the error should go away.
}
EDIT 2:
you don't need to read the file 2nd time in the using() clause.
Now please try the following:
string filename = openFileDialog1.FileName;
string[] line = File.ReadAllLines(filename);
var arrayTemp = new double[line.Length, 2];
for (int i = 0; i < line.Length; i++)
{
var data = line[i].Split(',');
arrayTemp[i, 0] = double.Parse(data[0]);
arrayTemp[i, 1] = double.Parse(data[1]);
}
Array.Copy(arrayTemp, GlobalDataClass.dDataArray, line.Length); // now the error should go away.

Your tempArray is out of the scope of you Array.Copy because it is inside of your for loop, you need to move it into the scope of your method call so the method can access it. (Similar to how GlobalDataClass.dDataArray is declared elsewhere)
//Array is now declared in an accessible scop
double[,] arrayTemp;
string filename = openFileDialog1.FileName;
string[] line = File.ReadAllLines(filename);
using (var reader2 = File.OpenText(#filename))
{
for (int i = 0; i < line.Length; i++)
{
string lines = reader2.ReadLine();
arrayTemp = new double[line.Length, 2];
var data = lines.Split(',');
GlobalDataClass.dDataArray[i, 0] = double.Parse(data[0]);
GlobalDataClass.dDataArray[i, 1] = double.Parse(data[1]);
}
Array.Copy(arrayTemp, GlobalDataClass.dDataArray, line.Length); //error the name "arrayTemp" does not exist in the current context.
}
Statements "deeper" into the { } hierarchy are only accessible to statements within them, and other child scopes in them. Parent scopes outside of the original brackets cannot access the variables.

looks like you array is out of scope because it's declared inside the for loop and you are trying to access it outside the for loop

I have answered on this link
To copy an array to another one, just use the "Clone()" function like the following:
This is your array list
object newArray = new object [row, column];
When you are creating another Array just use this code:
object[,] clonedArray = (object[,]) newArray.Clone();
Simple! Have fun!

Related

Reading a file and storing in 2d array on Form Load

I'm designing a simple Epos system as a project and I need to read my stock values in from a file at the beginning of the application in the form of a collection so I am trying to use a 2d int array but not having much luck.
The format of my txt file looks like this:
15,10,12,19,8
16,9,11,17,10
7,6,17,14,11
8,8,12,13,5
6,7,13,14,4
1,4,15,10,10
6,9,10,14,13
8,7,9,10,11
8,12,10,15,6
9,7,6,13,9
18,8,7,11,5
7,12,10,8,9
12,6,7,9,10
My code is as follows :
private void ReadToFileOpeningStock(int [,] Stock)
{
//create an array to hold data from file
string[] OneRowOfDataArray;
const int StockColumns = 13;
const int StockRows = 5;
int[,] STOCK_ITEMS = new int[StockColumns, StockRows];
try
{
// Declare a StreamReader variable.
StreamReader inputFile;
// Open the file and get a StreamReader object.
inputFile = File.OpenText("Opening StartingStock.txt");
while (!inputFile.EndOfStream)
{
OneRowOfDataArray = inputFile.ReadLine().Split(',');
for (int i = 0; i < StockColumns; i++)
{
//Here are the inner columns
for (int j = 0; j < StockRows; j++)
{
}
}
}
inputFile.Close();
}
catch
{
MessageBox.Show("Error");
}
I also have an empty array named Stock declared with the rest of thevariables that I have declared in the method name above.
int[,] Stock ;
How do I assign my text values to an array so that I can use it later in the application?
Sorry if I'm not being clear, I'm new to programming. Any help would be greatly appreciated. Thanks.
I changed it to use file.readallines as it is what I normally use. I've added an extra array to record all the lines, to then be separated with a split into OneRowOfDataArray.
I added outputs and the line to set the value to the STOCK_ITEMS. The only other thing I changed is I removed the spaces in between the rows on the txt file
static int[,] STOCK_ITEMS = new int[4, 3];
static void Main(string[] args)
{
//create an array to hold data from file
string[] RowsOfData;//contains rows of data
string[] OneRowOfDataArray;//will contain values seperated by the rows
const int StockColumns = 13;
const int StockRows = 5;
int[,] STOCK_ITEMS = new int[StockColumns, StockRows];
try
{
// Open the file and get a StreamReader object.
RowsOfData = File.ReadAllLines("Opening StartingStock.txt");//sets all lines and seperates them into ROWSOFDATA array
for (int i = 0; i < StockColumns; i++)
{
OneRowOfDataArray = RowsOfData[i].Split(',');//splits the values in each row seperate
Console.WriteLine();//new line when outputting the data
//Here are the inner columns
for (int j = 0; j < StockRows; j++)
{
STOCK_ITEMS[i, j] = Int32.Parse(OneRowOfDataArray[j]);//save to correct index in stock items
Console.Write("[" + STOCK_ITEMS[i, j] + "]");//output value from the row
}
}
}
catch
{
MessageBox.Show("Error");
}
}
txt file
15,10,12,19,8
16,9,11,17,10
7,6,17,14,11
8,8,12,13,5
6,7,13,14,4
1,4,15,10,10
6,9,10,14,13
8,7,9,10,11
8,12,10,15,6
9,7,6,13,9
18,8,7,11,5
7,12,10,8,9
12,6,7,9,10

C# Append at last line a character on all then one by one?

I'm making console c# app that actually takes all lines from text1 and append to it in the end of each line a text that is ".php?" or ".html? and these texts are also lines from text2, I want to print the first one in text2 in the end of each line in text1. Then take the second one in text2 and do the same Until it finishes text2?
Here's my code:
string[] resultConfig = File.ReadAllLines("keywords.txt");
string[] readParameters = File.ReadAllLines("param.txt");
for (int i = 0; i < readParameters.Length; i++)
{
for (int x = 0; x < resultConfig.Length ; x++)
{
resultConfig[x] = resultConfig[x] + readParameters[i];
Console.WriteLine(resultConfig[x]);
}
}
OUTPUT:
**
keyboards.php?.html?.asp?
karachi.php?.html?.asp?
keychain.php?.html?.asp?
in khobar.php?.html?.asp?
lebanon.php?.html?.asp?
lights.php?.html?.asp?
london.php?.html?.asp?
must have.php?.html?.asp?
**
**
WHAT IT SHOULD BE:
keyboards.php?
karachi.php?
keychain.php?
in khobar.php?
lebanon.php?
lights.php?
london.php?
must have.php?
keyboards.html?
karachi.html?
keychain.html?
in khobar.html?
lebanon.html?
lights.html?
london.html?
must have.html?
**
etc...
** KEYWORDS.TXT CONTAINS **
keyboards
karachi
keychain
in khobar
lebanon
lights
london
must have
** PARAM.TXT CONTAINS **
.php?
.asp?
.html?
Your problem is this line resultConfig[x] = resultConfig[x] + readParameters[i];. In this line you change your string in resultConfig[x] and since you're using a nested loop, this happens for every line in your *param.txt` file.
In order to write you desired result in the console try this code instead:
string[] resultConfig = File.ReadAllLines("keywords.txt");
string[] readParameters = File.ReadAllLines("param.txt");
for (int i = 0; i < readParameters.Length; i++)
{
for (int x = 0; x < resultConfig.Length ; x++)
{
string line = resultConfig[x] + readParameters[i];
Console.WriteLine(line);
}
}
You keep adding the parameter to the config and you should change the order of the loops and not change the value in the array.
Something like this:
string[] resultConfig = File.ReadAllLines("keywords.txt");
string[] readParameters = File.ReadAllLines("param.txt");
for (int x = 0; x < resultConfig.Length ; x++)
{
for (int i = 0; i < readParameters.Length; i++)
{
Console.WriteLine(resultConfig[x] + readParameters[i]);
}
}
It appears you want to save all these results in the resultConfig array, but you can't just add more items to an array than it was initialized with - you have to resize it first using Array.Resize(ref resultConfig, resultConfig.Length * readParameters.Length).
However, even then it will be a little tricky to append to the first set of items and then add new items for the additional parameters (it can be done if that's really necessary).
Instead I would create a new List<string> to save the results, and leave the initial arrays as they are:
string[] resultConfig =
{
"keyboards",
"karachi",
"keychain",
"in khobar",
"lebanon",
"lights",
"london",
"must have"
};
string[] readParameters = {".php?", ".html?", ".asp?"};
var allCombinations = new List<string>();
for (int i = 0; i < readParameters.Length; i++)
{
for (int x = 0; x < resultConfig.Length; x++)
{
allCombinations.Add(resultConfig[x] + readParameters[i]);
Console.WriteLine(resultConfig[x] + readParameters[i]);
}
}

C# DataTable column already exists issue

I'm attempting to import a CSV file into a DataTable, however the CSV contains headers that are the same. (For example, there are multiple "Date" headers for different form sections). To fix this, I decided to create a loop that will run through the headers and replace the duplicates or unwanted entries based on their position. I've replaced my replaceWith array with dummy entries, but my actual code does have the correct size to correlate with the replace array.
string[] columnNames = null;
string[] oStreamDataValues = null;
int[] error = {0,1,2,3,4,7,8,9,10,11,15,21,34,37,57,61,65,68,69,71,75,79,82,83,85,89,93,96,97,99,103,107,110,111,113,117,121,124,125,127,128,129,130,132,182,210,212,213,214,215,216,222,226,239};
int[] replace = {14,16,17,17,20,23,24,27,28,29,31,32,44,58,59,60,62,63,64,66,67,70,72,73,74,76,77,78,80,81,84,86,87,88,90,91,92,94,95,98,100,101,102,104,105,106,108,109,112,114,115,116,118,119,120,122,123,126,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180,184,186,187,188,190,191,192,194,195,196,198,199,200,202,203,204,206,207,208,209,236,242,243,244};
string[] replaceWith = {"Replace 1", "Replace 2", "Replace 3"};
string fix = "ignore_";
int inc = 00;
string entry = "";
while (!oStreamReader.EndOfStream)
{
string oStreamRowData = oStreamReader.ReadLine().Trim();
if (oStreamRowData.Length > 0)
{
//oStreamDataValues = Regex.Split(oStreamRowData, ",(?=(?:[^']*'[^']*')*[^']*$)");
oStreamDataValues = oStreamRowData.Split(',');
if (rowCount == 0)
{
rowCount = 1;
columnNames = oStreamDataValues;
for (int i = 0; i < columnNames.Length; i++)
{
for (int j = 0; j < error.Length; j++)
{
if (error[j] == i)
{
entry = fix + inc++;
}
}
for (int k = 0; k < replace.Length; k++)
{
if (replace[i] == i)
{
int add = 0;
entry = replaceWith[add++];
}
}
DataColumn oDataColumn = new DataColumn(entry, typeof(string));
oDataColumn.DefaultValue = string.Empty;
oDataTable.Columns.Add(oDataColumn);
}
}
}
I'm no coding expert, so my syntax/decision making isn't perfect.
However the error that I get is that A column named 'ignore_4' already belongs to this DataTable.
I assume something is incorrect in my loop logic.
I think you have overcomplicated the loops. You just need to keep an index of the current position in the array of errors and array of replaces.
string rep = "replace_"; // base string for replace fields
string fix = "ignore_"; // base string for ignore fields
// For demonstation purpose I have commented out this array. If you
// want every 'replace' column have its specific name then prepare this
// array with exactly the number of names required by the number of
// elements in the replace array
//
// string[] replaceWith = {"Replace 1", "Replace 2", "Replace 3"};
int idxErrors = 0; // Current position in the error array
int idxReplace = 0; // Current position in the replace array
int fixCounter = 1;
int repCounter = 1;
string entry = "";
for (int i = 0; i < columnNames.Length; i++)
{
// Is this the index of a column that should be ignored?
if (idxErrors < error.Length && i == error[idxErrors])
{
entry = fix + fixCounter.ToString("D2");
idxErrors++;
fixCounter++;
}
// Is this the index of a column that should have a different name??
else if (idxReplace < replace.Length && i == replace[idxReplace])
{
entry = rep + repCounter.ToString("D2");
// entry = replaceWith[repCounter];
idxReplace++;
repCounter++;
}
else
entry = columnNames[i];
// Now create the column
DataColumn oDataColumn = new DataColumn(entry, typeof(string));
oDataColumn.DefaultValue = string.Empty;
oDataTable.Columns.Add(oDataColumn);
}
In this example I have used the same pattern used for the ignored column also for the columns that need to have the name changed. If you want to give each renamed column a proper name, then you need to prepare an array with these proper names and this array should be of the same length of the replace array. Then use the idxReplace to take the correct name from the array of possible proper names.

Convert Excel Range to C# Array

I would like to convert an Excel Range to a C# Array with this code:
System.Array MyRange = (System.Array)range.cells.value;
for (int k = 0; k <= MyRange.Length; k++)
{
List<service_name> _ml = new List<service_name>();
for (int j = 1; j < dataitems.Count; j++)
{
// enter code here
}
}
And then iterate over it like in the above loop.
But this code does not work, and throws this Exception:
"Unable to cast object of type 'System.String' to type 'System.Array'."
Based on the help provided my Microsoft here, this is how I read and write an array in Excel.
var xlApp=new Microsoft.Office.Interop.Excel.Application();
var wb=xlApp.Workbooks.Open(fn, ReadOnly: false);
xlApp.Visible=true;
var ws=wb.Worksheets[1] as Worksheet;
var r=ws.Range["A2"].Resize[100, 1];
var array=r.Value;
// array is object[1..100,1..1]
for(int i=1; i<=100; i++)
{
var text=array[i, 1] as string;
Debug.Print(text);
}
// to create an [1..100,1..1] array use
var array2=Array.CreateInstance(
typeof(object),
new int[] {100, 1},
new int[] {1, 1}) as object[,];
// fill array2
for(int i=1; i<=100; i++)
{
array2[i, 1] = string.Format("Text{0}",i);
}
r.Value2=array2;
wb.Close(SaveChanges: true);
xlApp.Quit();
The error message in the original post occurs when the range consists of exactly one cell, because the resulting value's type is variant, and actually can be array, double, string, date, and null.
One solution can be that you check the cell count and act differently in case of exactly one cell.
My solution creates an array of cells. This works even if one or more cells are empty, which could causes a null object. (When all cells of the range are empty, Range.Cells.Value is null.)
System.Array cellArray = range.Cells.Cast<Excel.Range>().ToArray<Excel.Range>();
If you prefer Lists over Arrays (like I do), you can use this code:
List<Excel.Range> listOfCells = range.Cells.Cast<Excel.Range>().ToList<Excel.Range>();
Range can be one- or two-dimensional.
Finally, if you definitely need a string array, here it is:
string[] strArray = range.Cells.Cast<Excel.Range>().Select(Selector).ToArray<string>();
where Selector function looks like this:
public string Selector(Excel.Range cell)
{
if (cell.Value2 == null)
return "";
if (cell.Value2.GetType().ToString() == "System.Double")
return ((double)cell.Value2).ToString();
else if (cell.Value2.GetType().ToString() == "System.String")
return ((string)cell.Value2);
else if (cell.Value2.GetType().ToString() == "System.Boolean")
return ((bool)cell.Value2).ToString();
else
return "unknown";
}
I included "unknown" for the case I don't remember all data types that Value2 can return. Please improve this function if you find any other type(s).
NOTE: This example only works with a range that is MORE THAN ONE CELL. If the Range is only a single cell (1x1), Excel will treat it in a special way, and the range.Value2 will NOT return a 2-dimensional array, but instead will be a single value. It's these types of special cases that will drive you nuts, as well as zero and non-zero array lower bounds:
using Excel = Microsoft.Office.Interop.Excel;
private static void Test()
{
Excel.Range range = Application.ActiveWorkbook.ActiveSheet.Range["A1:B2"]; // 2x2 array
range.Cells[1, 2] = "Foo"; // Sets Cell A2 to "Foo"
dynamic[,] excelArray = range.Value2 as dynamic[,]; // This is a very fast operation
Console.Out.WriteLine(excelArray[1, 2]); // => Foo
excelArray[1, 2] = "Bar";
range.Value2 = excelArray; // Sets Cell A2 to "Bar", again a fast operation even for large arrays
Console.Out.WriteLine(range.Cells[1, 2]); // => Bar
Note that excelArray will have row and column lower bounds of 1:
Console.Out.WriteLine("RowLB: " + excelArray.GetLowerBound(0)); // => RowLB: 1
Console.Out.WriteLine("ColLB: " + excelArray.GetLowerBound(1)); // => ColLB: 1
BUT, if you declare a newArray in C# and assign it, then the lower bounds will be 0, but it will still work:
dynamic[,] newArray = new dynamic[2, 2]; // Same dimensions as "A1:B2" (2x2)
newArray[0, 1] = "Foobar";
range.Value2 = newArray; // Sets Cell A2 to "Foobar"
Console.Out.WriteLine(range.Cells[1, 2]); // => Foobar
Fetching this value out of the range will give you the original array with lower bounds of 0:
range.Cells[1, 2] = "Fubar";
dynamic[,] lastArray = range.Value2 as dynamic[,];
Console.Out.WriteLine(lastArray[0, 1]); // => Fubar
Console.Out.WriteLine("RowLB: " + lastArray.GetLowerBound(0)); // => RowLB: 0
Console.Out.WriteLine("ColLB: " + lastArray.GetLowerBound(1)); // => ColLB: 0
}
Working with Excel Interop can be daunting as there are many special cases like this in the codebase, but I hope this helps clarify at least this one.
The error means that the value is a string, so you can't convert it directly to array.
If the value is for example comma delimeted string you can use Split to get an array:
string[] MyRange = (range.Cells.Value + "").Split(',');
for (int k = 0; k < MyRange.Length; k++)
{
//...loop here...
}
Also fixed your loop, you were going to get Index Out of Bounds error.
Late to the conversation, but here is a method to do this:
static string[][] GetStringArray(Object rangeValues)
{
string[][] stringArray = null;
Array array = rangeValues as Array;
if (null != array)
{
int rank = array.Rank;
if (rank > 1)
{
int rowCount = array.GetLength(0);
int columnCount = array.GetUpperBound(1);
stringArray = new string[rowCount][];
for (int index = 0; index < rowCount; index++)
{
stringArray[index] = new string[columnCount-1];
for (int index2 = 0; index2 < columnCount; index2++)
{
Object obj = array.GetValue(index + 1, index2 + 1);
if (null != obj)
{
string value = obj.ToString();
stringArray[index][index2] = value;
}
}
}
}
}
return stringArray;
}
called with:
string[][] rows = GetStringArray(range.Cells.Value2);
The issue is because ,when your range becomes a single cell ,and "range.value"/"range.cell.value" means String value,this string cannot be put into object array.
So check if your range has only one cell or more and do according to that

Array of string not working

I use a simple array: contentHouseOne[] that contains strings. But in the Do/While loop it isn't working! It seems like the code don't understand that it's a string when a new object is to be created!? It works when I hardcode the string like I show below. Help is preciated! Thanks!
This isn't working:
listHouseParts.Add(new HousePart(content, contentHouseOne[i], newPosition));
But this works:
listHouseParts.Add(new HousePart(content, "100x100", newPosition));
EDIT:
Here are some code to declare arrays
string[] contentHouseOne = new string[] { "ruta100x100Red",
"ruta100x100Grey",
"ruta100x100Green",
"ruta100x100Yellow",
"ruta100x100Blue" };
bool[,] occupiedPositions = new bool[500,500];
Here are some code to set all grid positions to false
for (int i = 0; i < gridCol; i++)
for (int ii = 0; ii < gridRow; ii++)
occupiedPositions[i, ii] = false;
And finally here are the code that I have the problem
int i = 0;
do
{
Vector2 newPosition = NewRandomPosition;
if (occupiedPositions[(int)newPosition.X, (int)newPosition.Y] == false)
{
listHouseParts.Add(new HousePart(content,
contentHouseOne[i], newPosition));
occupiedPositions[(int)newPosition.X, (int)newPosition.Y] = true;
i++;
}
}
while (i <= 5);
Your string array includes five elements:
string[] contentHouseOne = new string[] { "ruta100x100Red",
"ruta100x100Grey",
"ruta100x100Green",
"ruta100x100Yellow",
"ruta100x100Blue" };
But your while loop ends if your running variable i is greater than 5
while (i <= 5);
which causes a IndexOutOfBounds exception on contentHouseOne, because the 6th element at index 5 isn't defined.
You should change your while condition to (i < 5).
Try this so atleast you know if its empty or not
HousePart housePart = new HousePart();
housePart.Content = content;
if (!string.IsNullOrEmpty(contentHouseOne[i]))
housePart.ContentHouseOne = contentHouseOne[i];
else
housePart.ContentHouseOne = string.Empty;
housePart.NewPosition = newPosition;
listHouseParts.Add(housePart);

Categories

Resources