Write list to csv file c# - c#

Imagine i have 2 lists filled with values. I want all the elements from the first list, written into the first column, all the elements from the second list written into the second column and so on.
If both list have the same size, this works fine:
for (int i = 0; i < valueArray.Count(); i++)
{
var newLine = string.Format("{0},{1}", valueArray.ElementAt(i), secondValueArray.ElementAt(i));
sw.Write(newLine);
}
My problem is that if the lists have different sizes, code fails with out of range exception obviously. I tried adding ',' between columns but it's not working.

Instead of ElementAt you should use ElementAtOrDefault :
According to msdn it
Returns the element at a specified index in a sequence or a default
value if the index is out of range.

try this :
List<int?> valueArray = new List<int?>();
List<int?> secondValueArray = new List<int?>();
//... fill lists
valueArray.Add( 1 );
valueArray.Add(2);
valueArray.Add(3);
secondValueArray.Add( 4 );
while (valueArray.Count > secondValueArray.Count)
secondValueArray.Add(null);
while (secondValueArray.Count > valueArray.Count)
valueArray.Add(null);
for (int i = 0; i < valueArray.Count(); i++)
{
var newLine = string.Format("{0},{1}", valueArray.ElementAt(i), secondValueArray.ElementAt(i));
Console.WriteLine(newLine);
}
;
Result :
1,4
2,
3,

As mentioned before, use ElementAtOrDefault(). And check which array is the longest one. Furthermore, you might want to write an empty string instead of NULL if there's no value.
int count = Math.Max(firstArray.Count(), secondArray.Count());
for (int i = 0; i < count; i++)
{
var value1 = firstArray.ElementAtOrDefault(i) ?? String.Empty;
var value2 = secondArray.ElementAtOrDefault(i) ?? String.Empty;
var newLine = string.Format("{0},{1}", value1, value2);
sw.Write(newLine);
}

Related

assigning numbers entered in a row to an array 3 6 23 12 4 a[0]=3 a[1]=6 a[2]=23 a[3]=12 a[4]=10

string[] n = Console.ReadLine().Split();
for (int i = 1; i <6; i++)
{
int[] a = long.Parse(n[i]);
}
If each number in a row separated with whitespace - you can use your Split more efficiently:
int[] array = Console.ReadLine().Split().Select(int.Parse).ToArray(); // Improved according to #Caius Jard comment
If need array of longs - replace int.Parse with long.Parse and declare variable as long[] array.
You need to add using System.Linq to get access to ToArray extension method.
EDIT.
Insprired by #Caius Jard, non-LINQ version:
// Read input line and split it by whitespace (default)
string[] values = Console.ReadLine().Split();
// Declare arrays for Int or Long values.
// Arrays sizes equals to size of array of input values
int[] arrayOfInts = new int[values.Length];
long[] arrayOfLongs = new long[values.Length];
// Iterate with for loop over amount of input values.
for (int i = 0; i < values.Length; i++)
{
// Convert trimmed input value to Int32
arrayOfInts[i] = int.Parse(values[i].Trim());
// Or to Int64
arrayOfLongs[i] = long.Parse(values[i].Trim());
}
int.Parse and long.Parse may be replaced with Convert.ToInt32 and Convert.ToInt64 if needed.
Please, don't use magic constants: i < 6. Here 6 doesn't necessary equal to n.Length.
You can put it as
string[] n = Console.ReadLine().Split();
List<int> list = new List<int>();
for (int i = 0; i < n.Length; ++i) {
if (int.TryParse(n[i], out int value))
list.Add(value);
else {
// Invalid item within user input, say "bla-bla-bla"
//TODO: either reject the input or ignore the item (here we ignore)
}
}
if (list.Count == a.Length) {
// We have exactly a.Length - 6 valid integer items
for (int i = 0; i < a.Length; ++i)
a[i] = list[i];
}
else {
//TODO: erroneous input: we have too few or too many items
}

Copy String byte Array contents to another array and Prefix 0 to single digits in C#

I have String array named "string_array_packet" which contains
FA,11,1,4,90,6C,E7,72,0,0,0,8,80,0,8,80,7B,
Now i need to copy the contents between first and last index of array and store it in another array and then need to prefix 0 to single digits
11,1,4,90,6C,E7,72,0,0,0,8,80,0,8,80,
What I have done so far is
var sourceStartIndex = 1;
var destinationLength = string_array_packet.Length - 2;
Console.WriteLine(string_array_packet.Length);
Console.WriteLine(destinationLength);
var destinationStartIndex = 0;
var destination = new string[destinationLength];
Array.Copy(string_array_packet, sourceStartIndex,
destination, destinationStartIndex, destinationLength);
Not sure how to proceed after this.
This can be done much easier with Linq (using System.Linq required):
var sourceStartIndex = 1;
var destinationLength = string_array_packet.Length - 2;
var strings = string_array_packet.Skip(sourceStartIndex)
.Select(x => x.Length == 1 ? "0" + x :x)
.Take(destinationLength)
.ToArray();
Alternatively, if you're not familiar with the Enumerable methods then add the following imperative approach to complete your code:
for (int i = 0; i < destination.Length; i++)
if (destination[i].Length == 1)
destination[i] = "0" + destination[i];

Getting the column totals in a 2D array but it always throws FormatException using C#

I am planning to get an array of the averages of each column.
But my app crashes at sum[j] += int.Parse(csvArray[i,j]); due to a FormatException. I have tried using Convert.ToDouble and Double.Parse but it still throws that exception.
The increments in the for loop start at 1 because Row 0 and Column 0 of the CSV array are strings (names and timestamps). For the divisor or total count of the fields that have values per column, I only count the fields that are not BLANK, hence the IF statement. I think I need help at handling the exception.
Below is the my existing for the method of getting the averages.
public void getColumnAverages(string filePath)
{
int col = colCount(filePath);
int row = rowCount(filePath);
string[,] csvArray = csvToArray(filePath);
int[] count = new int[col];
int[] sum = new int[col];
double[] average = new double[col];
for (int i = 1; i < row; i++)
{
for (int j = 1; j < col; j++)
{
if (csvArray[i,j] != " ")
{
sum[j] += int.Parse(csvArray[i,j]);
count[j]++;
}
}
}
for (int i = 0; i < average.Length; i++)
{
average[i] = (sum[i] + 0.0) / count[i];
}
foreach(double d in average)
{
System.Diagnostics.Debug.Write(d);
}
}
}
I have uploaded the CSV file that I use when I test the prototype. It has BLANK values on some columns. Was my existing IF statement unable to handle that case?
There are also entries like this 1.324556-e09due to the number of decimals I think. I guess I have to trim it in the csvToArray(filePath) method or are there other efficient ways? Thanks a million!
So there are a few problems with your code. The main reason for your format exception is that after looking at your CSV file your numbers are surrounded by quotes. Now I can't see from your code exactly how you convert your CSV file to an array but I'm guessing that you don't clear these out - I didn't when I first ran with your CSV and experienced the exact same error.
I then ran into an error because some of the values in your CSV are decimal, so the datatype int can't be used. I'm assuming that you still want the averages of these columns so in my slightly revised verion of your method I change the arrays used to be of type double.
AS #musefan suggested, I have also changed the check for empty places to use the IsNullOrWhiteSpace method.
Finally when you output your results you receive a NaN for the first value in the averages column, this is because when you don't take into account that you never populate the first position of your arrays so as not to process the string values. I'm unsure how you'd best like to correct this behaviour as I'm not sure of the intended purpose - this might be okay - so I've not made any changes to this for the moment, pop a mention in the comments if you want help on how to sort this!
So here is the updated method:
public static void getColumnAverages(string filePath)
{
// Differs from the current implementation, reads a file in as text and
// splits by a defined delim into an array
var filePaths = #"C:\test.csv";
var csvArray = File.ReadLines(filePaths).Select(x => x.Split(',')).ToArray();
// Differs from the current implementation
var col = csvArray[0].Length;
var row = csvArray.Length;
// Update variables to use doubles
double[] count = new double[col];
double[] sum = new double[col];
double[] average = new double[col];
Console.WriteLine("Started");
for (int i = 1; i < row; i++)
{
for (int j = 1; j < col; j++)
{
// Remove the quotes from your array
var current = csvArray[i][j].Replace("\"", "");
// Added the Method IsNullOrWhiteSpace
if (!string.IsNullOrWhiteSpace(current))
{
// Parse as double not int to account for dec. values
sum[j] += double.Parse(current);
count[j]++;
}
}
}
for (int i = 0; i < average.Length; i++)
{
average[i] = (sum[i] + 0.0) / count[i];
}
foreach (double d in average)
{
System.Diagnostics.Debug.Write(d + "\n");
}
}

Why im getting 0 all the time when using indexOf?

for (int i = 0; i < links.Count; i++)
{
int f = links[i].IndexOf("http");
}
links is List<string>
For example in index 0 I have: http://test/107281.shtml#34
I want to extract from this link only this:
http://test/107281.shtml without the #34 in the end.
But for the start why f return 0 all the time ?
It's right...., cause this string "http" start index is 0, if couldn't found string, IndexOf will return -1...
The first char in a string is located at index 0, so in the string http://test/107281.shtml#34 as http is the first thing in the string its located at index 0...
To extract you can use either regex or indexOf("#") in combination with substring.
The indexOf() method returns the position of the first occurrence of a specified value in a string.
var str = "Hello world, welcome to the universe.";
var n = str.indexOf("welcome");
Output wil be : 13
which is the position number.
Next you remove from which position you want to delete.
I guess you are looking for something like:
for (int i = 0; i < links.Count; i++)
{
int f = links[i].IndexOf("#");
}
This should give you the index of the first #.
IndexOf("http") should give you 0 as http is at index 0.
To get the string you are seeking:
for (int i = 0; i < links.Count; i++)
{
var url = links[i].Substring(0, links[i].IndexOf("#"));
}
Example using your demo string HERE.
List<string> link_list = new List<string> { "http://test/107281.shtml#34", "http://test/107281.shtml#35" };
List<string> new_list = new List<string>();
foreach (var item in link_list)
{
string bb = item.Substring(0, item.ToString().IndexOf("#"));
new_list.Add(bb);
}

Detecting an empty array without looping

How can i find out an array is empty or not, without looping?!
is there any method or anything else?
I mean, in some code like this:
string[] names = new string[5];
names[0] = "Scott";
names[1] = "jack";
names[2] = null;
names[3] = "Jones";
names[4] = "Mesut";
// or
int[] nums = new int[4];
nums[0] = 1;
// nums[1] = 2;
nums[2] = 3;
nums[3] = 4;
or some code like this:
using System;
class Example
{
static void Main()
{
int size = 10;
int counter;
string[] str = new string[size];
for (counter = 0; counter < size; counter++)
{
str[counter] = "A" + counter;
}
str[3] = null;
if (counter == size)
Console.WriteLine("Our array is full!");
if(counter < size)
Console.WriteLine("Our array is not full");
for (int i = 0; i < size; i++)
{
Console.WriteLine(str[i]);
}
}
}
is there anything else for detecting an empty array without looping?
An array just contains a number of elements. There's no concept of an array being "empty" just because each element happens to contain the default value (0, null, or whatever).
If you want a dynamically sized collection, you should use something like List<T> instead of an array.
If you want to detect whether any element of a collection (whether that's a list, an array or anything else) is a non-default value, you have to do that via looping. (You don't have to loop in your source code, but there'll be looping involved somewhere...)
There is no other way than looping through, even LINQ also does the looping automatically.
Instead, use a list<> and check if (listName!=null && listName.Length!=0)
Hope it helps :)
You can use LINQ for that, to check if any element is empty in the array you just can do:
var hasNulls = myArray.Any( a => a == null );
Or if you want to select the ones with values:
var notNulls = myArray.Where( a => a != null );

Categories