convert from list[] to two dimensional object[,] array [C#] - c#

I pull csv data using StreamReader into a List<string[]>, which I then want to convert to a two dimensional array in order to extract data into another similar array using logical rules with looping (I want to be able to access [row,column] data individually). Here is the csv method:
public static object[] CsvData(string filePath)
{
List<string[]> csvContent = new List<string[]>();
using (StreamReader sr = new StreamReader(filePath))
{
while (!sr.EndOfStream)
{
string[] lineArr = sr.ReadLine().Split(',');
csvContent.Add(lineArr);
}
}
return csvContent.ToArray();
}
Currently my object array output is one dimensional. I have tried modifying it in various ways but can't get the dimensions to add up to give me a object[,] on the return. I am using object arrays since the data has more than one type.

it should be:
public static List<object[]> CsvData()
{
List<object[]> csvContent = new List<object[]>();
///Code here
return csvContent;
}
or
public static List<string[]> CsvData()
{
List<string[]> csvContent = new List<string[]>();
///Code here
return csvContent;
}

This should get you started:
var rows = csvContent.Count - 1;
var cols = csvContent.Max(x => x.Length + 1);
string[,] arr = new string[rows,cols];
foreach (var (x,index) in csvContent.SelectMany(x => x).Select((x,index) => (x,index))) {
var row = index / cols;
var col = index % cols;
arr[row,col] = x;
}

Related

Skip blank rows in 2D string array effectively [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
Consider 2D array like this one:
With the following code the empty rows are skipped:
public static string[,] SkipBlankRows(this string[,] array2D)
{
var columns = array2D.GetLength(1);
var rows = array2D.GetLength(0);
var temp = new List<string[]>();
for (var r = 0; r < rows; r++)
{
var row = new string[columns];
for (var c = 0; c < columns; c++)
{
row[c] = array2D[r, c];
}
if (row.All(itm => string.IsNullOrWhiteSpace(itm)))
continue;
temp.Add(row);
}
string[,] result = new string[temp.Count(), columns];
rows = temp.Count();
for (int r = 0; r < rows; r++)
{
var row = temp[r];
for (var c = 0; c < row.Length; c++)
{
result[r,c]=row[c];
}
}
return result;
}
Usage:
void Main()
{
var x = new string[,] { { "", "", "" }, { "", "X", "" }, { "X", "X", "X" }, { "", "", "" }, {"X","","X"}, {"X","X","X"}};
var y = x.SkipBlankRows();
}
Result:
The result should be 2D-array of string where the blank rows will not be there.
The code looks awkward to me, is it possible to do it better e.g. to involve linq?
You could use LINQ to get the string[,] to an IEnumerable<IEnumerable<string>> with the empty rows removed, then put the IEnumerable<IEnumerable<string>> back into a string[,]. I'm not aware of any way with LINQ to project an IEnumerable<IEnumerable<string>> into a string[,], so I just used nested foreach loops.
public static string[,] SkipBlankRows(this string[,] array2D)
{
int columnCount = array2D.GetLength(1);
var withoutEmptyLines = array2D
.Cast<string>() // Flatten the 2D array to an IEnumerable<string>
.Select((str, idx) => new { str, idx }) // Select the string with its index
.GroupBy(obj => obj.idx / columnCount) // Group the items into groups of "columnCount" items
.Select(grp => grp.Select(obj => obj.str)) // Select the groups into an IEnumerable<IEnumerable<string>>
.Where(strs => !strs.All(str => string.IsNullOrWhiteSpace(str))); // Filter empty rows;
// Put the IEnumerable<IEnumerable<string>> into a string[,].
var result = new string[withoutEmptyLines.Count(), columnCount];
int rowIdx = 0;
foreach (var row in withoutEmptyLines)
{
int colIdx = 0;
foreach (var col in row)
{
result[rowIdx, colIdx++] = col;
}
rowIdx++;
}
return result;
}
LINQ was intended to process and produce collections rather than multidimensional arrays. You can replace the first for loop with some LINQ that's a little more expressive, but you can't really get away from using for loops for repopulating the new array:
public static string[,] SkipBlankRows(this string[,] array2D)
{
var columns = array2D.GetLength(1);
var rows = array2D.GetLength(0);
var temp = Enumerable.Range(0, rows)
.Select(i => Enumerable.Range(0, columns).Select(j => array2D[i, j]).ToList())
.Where(row => !row.All(string.IsNullOrEmpty))
.ToList();
string[,] result = new string[temp.Count, columns];
rows = temp.Count;
for (int r = 0; r < rows; r++)
{
var row = temp[r];
for (var c = 0; c < row.Count; c++)
{
result[r, c] = row[c];
}
}
return result;
}
Of course, if you're willing to bring in a couple of helper methods to abstract away the conversion to and from rows, you can end up with a highly efficient and very easy-to-read code.
How to get a complete row or column from 2D array in C#
Converting jagged array to 2D array C#
It depends on what you want your output to look like, do you just want to skip over the blank strings and have a list of values? Or do you want your data to still be in the multi-dimentional array?
If your answer to this question is "the second one" then your code is fine.
If you just want a list of all of the values out of the multi-dimentional array you could write something like:
public static IEnumerable<string> SkipBlankRows(this string[,] array2D)
{
return (from string s in array2D where !string.IsNullOrWhiteSpace(s) select s);
}
This returns a flat structure of values from the array.
Hope this helps

Splitting of dataset based on number of rows in to multiple tables

I have a situation where I need to Split dataset results in to multiple tables eventually in to an array based on number of rows.
Ex: my dataset has 34 rows with a url column, I need to split 34 rows in to 4 data tables (10,10,10 remaining 4) and eventually add to an array. I am using a forms windows application. Itried something like below however every time i add records to array it adds entire dataset. Any help would be appreciated.
private DataSet Process(DataSet ds)
{
string[] Array1 = new string[10];
string[] Array2 = new string[10];
string[] Array3 = new string[10];
string[] Array4 = new string[10];
int COunt = ds.Tables[0].DefaultView.Count;
int NoOfArraysToCreate = COunt/10 + 1;
for (int i = 0; i <= NoOfArraysToCreate; i++ )
{
if (i == 0)
{
foreach (DataRow drs in ds.Tables[0].Rows)
{
List<String> myList = new List<string>();
myList.Add(drs["Url"].ToString());
Array1 = myList.ToArray();
}
}
else if (i == 1)
{
foreach (DataRow drs in ds.Tables[0].Rows)
{
List<String> myList = new List<string>();
myList.Add(drs["Url"].ToString());
Array2 = myList.ToArray();
}
}
else if (i == 2)
{
foreach (DataRow drs in ds.Tables[0].Rows)
{
List<String> myList = new List<string>();
myList.Add(drs["Url"].ToString());
Array3 = myList.ToArray();
}
}
else if (i == 3)
{
foreach (DataRow drs in dsURLsList.Tables[0].Rows)
{
List<String> myList = new List<string>();
myList.Add(drs["Url"].ToString());
Array4 = myList.ToArray();
}
}
}
It seems you are looping through all DataTable rows for each of your pages.
I would suggest you only loop over your rows once:
private List<List<string>> Process(DataSet ds, int pageSize)
{
List<List<string>> result = new List<List<string>>();
int COunt = ds.Tables[0].DefaultView.Count;
int NoOfArraysToCreate = COunt / pageSize + 1;
IEnumerable<DataRow> collection = ds.Tables[0].Rows.Cast<DataRow>(); //I find it easier to work with enumerables as it allows for LINQ expressions as below
for (int i = 0; i < NoOfArraysToCreate; i++)
{
result.Add(collection.Skip(i*pageSize)
.Take(pageSize)
.Select(r => r["Url"].ToString())
.ToList());
}
Parallel.ForEach(result, (page) =>
{
Parallel.ForEach(page, (url) => {}); // process your strings in parallel
});
return result;//I see you convert your string arrays back to DataSet, but since I don't know the table definition, I'm just returning the lists
}
void Main()
{
// this is just a test code to illustrate my point, yours will be different
var ds = new DataSet();
var dt = new DataTable();
dt.Columns.Add("Url", typeof(string));
for (int i = 0; i < 34; i++) {
dt.Rows.Add(Guid.NewGuid().ToString());//generating some random strings, ignore me
}
ds.Tables.Add(dt);
//---------------------------------------
Process(ds, 10);// calling your method
}
of course there are ways to do it with for loops as well, but I'd leave that for you to explore.
I would also say hardcoding table numbers into your method usually is considered a code smell, but since I don't know your context I will not make any further changes

How can I split a string to store contents in two different arrays in c#?

The string I want to split is an array of strings.
the array contains strings like:
G1,Active
G2,Inactive
G3,Inactive
.
.
G24,Active
Now I want to store the G's in an array, and Active or Inactive in a different array. So far I have tried this which has successfully store all the G's part but I have lost the other part. I used Split fucntion but did not work so I have tried this.
int i = 0;
for(i = 0; i <= grids.Length; i++)
{
string temp = grids[i];
temp = temp.Replace(",", " ");
if (temp.Contains(' '))
{
int index = temp.IndexOf(' ');
grids[i] = temp.Substring(0, index);
}
//System.Console.WriteLine(temp);
}
Please help me how to achieve this goal. I am new to C#.
If I understand the problem correctly - we have an array of strings Eg:
arrayOfStrings[24] =
{
"G1,Active",
"G2,Inactive",
"G3,Active",
...
"G24,Active"
}
Now we want to split each item and store the g part in one array and the status into another.
Working with arrays the solution is to - traverse the arrayOfStrings.
Per each item in the arrayOfStrings we split it by ',' separator.
The Split operation will return another array of two elements the g part and the status - which will be stored respectively into distinct arrays (gArray and statusArray) for later retrieval. Those arrays will have a 1-to-1 relation.
Here is my implementation:
static string[] LoadArray()
{
return new string[]
{
"G1,Active",
"G2,Inactive",
"G3,Active",
"G4,Active",
"G5,Active",
"G6,Inactive",
"G7,Active",
"G8,Active",
"G9,Active",
"G10,Active",
"G11,Inactive",
"G12,Active",
"G13,Active",
"G14,Inactive",
"G15,Active",
"G16,Inactive",
"G17,Active",
"G18,Active",
"G19,Inactive",
"G20,Active",
"G21,Inactive",
"G22,Active",
"G23,Inactive",
"G24,Active"
};
}
static void Main(string[] args)
{
string[] myarrayOfStrings = LoadArray();
string[] gArray = new string[24];
string[] statusArray = new string[24];
int index = 0;
foreach (var item in myarrayOfStrings)
{
var arraySplit = item.Split(',');
gArray[index] = arraySplit[0];
statusArray[index] = arraySplit[1];
index++;
}
for (int i = 0; i < gArray.Length; i++)
{
Console.WriteLine("{0} has status : {1}", gArray[i] , statusArray[i]);
}
Console.ReadLine();
}
seems like you have a list of Gxx,Active my recomendation is first of all you split the string based on the space, which will give you the array previoulsy mentioned doing the next:
string text = "G1,Active G2,Inactive G3,Inactive G24,Active";
string[] splitedGItems = text.Split(" ");
So, now you have an array, and I strongly recommend you to use an object/Tuple/Dictionary depends of what suits you more in the entire scenario. for now i will use Dictionary as it seems to be key-value
Dictionary<string, string> GxListActiveInactive = new Dictionary<string, string>();
foreach(var singleGItems in splitedGItems)
{
string[] definition = singleGItems.Split(",");
GxListActiveInactive.Add(definition[0], definition[1]);
}
What im achiving in this code is create a collection which is key-value, now you have to search the G24 manually doing the next
string G24Value = GxListActiveInactive.FirstOrDefault(a => a.Key == "G24").Value;
just do it :
var splitedArray = YourStringArray.ToDictionary(x=>x.Split(',')[0],x=>x.Split(',')[1]);
var gArray = splitedArray.Keys;
var activeInactiveArray = splitedArray.Values;
I hope it will be useful
You can divide the string using Split; the first part should be the G's, while the second part will be "Active" or "Inactive".
int i;
string[] temp, activity = new string[grids.Length];
for(i = 0; i <= grids.Length; i++)
{
temp = grids[i].Split(',');
grids[i] = temp[0];
activity[i] = temp[1];
}

C# Populate An Array with Values in a Loop

I have a C# console application where an external text file is read. Each line of the file has values separated by spaces, such as:
1 -88 30.1
2 -89 30.1
So line one should be split into '1', '-88', and '30.1'.
What I need to do is to populate an array (or any other better object) so that it duplicate each line; the array should have 3 elements per row. I must be having a brain-lock to not figure it out today. Here's my code:
string line;
int[] intArray;
intArray = new int[3];
int i = 0;
//Read Input file
using (StreamReader file = new StreamReader("Score_4.dat"))
{
while ((line = file.ReadLine()) != null && line.Length > 10)
{
line.Trim();
string[] parts;
parts = line.Split(' ');
intArray[0][i] = parts[0];//error: cannot apply indexing
i++;
}
}
Down the road in my code, I intend to make some API calls to a server by constructing a Json object while looping through the array (or alternate object).
Any idea?
Thanks
If you only need the data to be transferred to JSON then you don't need to process the values of the data, just reformat it to JSON arrays.
As you don't know the number of lines in the input file, it is easier to use a List<>, whose capacity expands automatically, to hold the data rather than an array, whose size you would need to know in advance.
I took your sample data and repeated it a few times into a text file and used this program:
static void Main(string[] args)
{
string src = #"C:\temp\Score_4.dat";
List<string> dataFromFile = new List<string>();
using (var sr = new StreamReader(src))
{
while (!sr.EndOfStream)
{
string thisLine = sr.ReadLine();
string[] parts = thisLine.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 3)
{
string jsonArray = "[" + string.Join(",", parts) + "]";
dataFromFile.Add(jsonArray);
}
else
{
/* the line did not have three entries */
/* Maybe keep a count of the lines processed to give an error message to the user */
}
}
}
/* Do something with the data... */
int totalEntries = dataFromFile.Count();
int maxBatchSize = 50;
int nBatches = (int)Math.Ceiling((double)totalEntries / maxBatchSize);
for(int i=0;i<nBatches;i+=1)
{
string thisBatchJsonArray = "{\"myData\":[" + string.Join(",", dataFromFile.Skip(i * maxBatchSize).Take(maxBatchSize)) + "]}";
Console.WriteLine(thisBatchJsonArray);
}
Console.ReadLine();
}
to get this output:
{"myData":[[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1]]}
{"myData":[[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1]]}
It should be easy to adjust the format as required.
I would create a custom Item class and then populate a list, for easy access and sorting, with self contained items. something like:
public Class MyItem
{
public int first { get; set; }
public int second { get; set; }
public float third { get; set; }
public MyItem(int one, int two, float three)
{
this.first = one;
this.second = two;
this.third = three;
}
}
then you could do:
List<MyItem> mylist = new List<MyItem>();
and then in your loop:
using (StreamReader file = new StreamReader("Score_4.dat"))
{
while ((line = file.ReadLine()) != null && line.Length > 10)
{
line.Trim();
string[] parts;
parts = line.Split(' ');
MyItem item = new Item(Int32.Parse(parts[0]),Int32.Parse(parts[1]),Float.Parse(parts[2]));
mylist.Add(item);
i++;
}
}
As there are numbers like 30.1 so int is not suitable for this, and also it must not be a double[] but double[][]:
string[] lines = File.ReadAllLines("file.txt");
double[][] array = lines.Select(x => s.Split(' ').Select(a => double.Parse(a)).ToArray()).ToArray();
Issue is that int array is single dimensional.
My suggestion is that you can put a class with 3 properties and populate a list of class there. It's better to have class with same property names that you require to build JSON. So that you can easily serialize this class to JSON using some nugets like Newtonsoft and make api calls easily.
Your int array is a single dimensional array yet you're trying to index it like a multidemensional array. It should be something like this:
intArray[i] = parts[0]
(However you'll need to handle converting to int for parts that are fractional)
Alternatively, if you want to use a multidimensional array, you have to declare one.
int[][] intArray = new int[*whatever your expected number of records are*][3]
Arrays have a static size. Since you're reading from a file and may not know how many records there are until your file finishes reading, I recommend using something like a List of Tuples or a Dictionary depending on your needs.
A dictionary will allow you to have quick lookup of your records without iterating over them by using a key value pair, so if you wanted your records to match up with their line numbers, you could do something like this:
Dictionary<int, int[]> test = new Dictionary<int, int[]>();
int lineCount = 1;
while ((line = file.ReadLine()) != null && line.Length > 10)
{
int[] intArray = new int[3];
line.Trim();
string[] parts = line.Split(' ');
for (int i = 0; i < 3; i++)
{
intArray[i] = int.Parse(parts[i]);
}
test[lineCount] = intArray;
lineCount++;
}
This will let you access your values by line count like so:
test[3] = *third line of file*

C# List to Array Problem

Still new to C# so be gentle :)
I have some code which reads in a CSV file and stores the output in a List. I used a List instead of an Array as the number of entries in the CSV is undetermined. Once the List is created from the file I then want to pass it to a Shell sort method as this is the purpose of the program. To do this I first want to convert the list to an array of integers. I have tried the .ToArray method but it doesnt seem to be working for me. I get an exception
Cannot Implicilty convert type String[][] to string[].
I know I am doing something stupid but cant seem to find out what... Any help would be appreciated.
//Import DAT file and format it.
public int[] ImportDat(string path)
{
List<string[]> loadedData = new List<string[]>();
loadedData.Clear();
try
{
using (StreamReader readCSV = new StreamReader(path))
{
string line;
string[] row;
while ((line = readCSV.ReadLine()) != null)
{
row = line.Split(',');
loadedData.Add(row);
}
}
}
catch
{
MessageBox.Show("Import Failed. Please check the file is in the same folder as the executable");
}
string[] MyArray = loadedData.ToArray();
//temp Array to return a value
int[] numbers = new int[5] { 1, 2, 3, 4, 5 };
return numbers;
}
It seems like you really want a one dimensional list of numbers from your CSV file, but you are treating each row separately right now. If that is the case then use:
loadedData.AddRange(row);
instead of:
loadedData.Add(row);
and declare loadedData as List<string>. Now you still would have to do the conversion to int, since your method returns a list of int.Using LINQ you could do:
List<int> results = loadedData.Select(s=> Convert.ToInt32(s)).ToList();
Your method also could be fully expressed with LINQ like this:
public int[] ImportDat(string path)
{
List<int> result = File.ReadAllLines(path)
.Select(line => line.Split(','))
.SelectMany(s => s)
.Select( s=> Convert.ToInt32(s))
.ToList();
return result;
}
Your variable loadedData is a List of string arrays. Calling .ToArray() on it will return a string[][] (2 dimensional array), not a string[].
Why don't you just use the list and convert the numbers right away?
public int[] ImportDat(string path)
{
List<int> loadedData = new List<int>();
loadedData.Clear();
try
{
using (StreamReader readCSV = new StreamReader(path))
{
string line;
string[] row;
while ((line = readCSV.ReadLine()) != null)
{
row = line.Split(',');
foreach(var token in row)
{
loadedData.Add(Convert.ToInt32(token));
}
}
}
}
catch
{
MessageBox.Show("Import Failed. Please check the file is in the same folder as the executable");
}
return loadedData.ToArray();
}
You are declaring loadedData as a list of string arrays. You should just do
List<string> loadedData = new List<string>();
The problem is that each item in your List, is an array of strings.
it's not a list of string.
hench, you should make your "MyArray" a two dimensional array of strings.
in other words, an array of arrays of strings.
so in short: string[][] MyArray = loadedData.ToArray();
Perhaps you can modify this code to suit your needs?
List<int> numbersList = new List<int>();
string input = "2,4,6,3";
string[] numbersStringArray = input.Split(',');
foreach (var numberString in numbersStringArray)
{
numbersList.Add(Convert.ToInt32(numberString));
}
int[] numbersArray = numbersList.ToArray<int>();

Categories