I need to read from a CSV file (separated via “;”) and a new file should be created containing the transposed (rotated) table:
my input file:
The tool shall be able to receive the filename of the table from the user and load the table to transpose the content.
The tool shall be able to save the transposed table in a new file with the filename of the input file and extended with “transposed” (“filename_transposed.csv”).
my Code
public void ReadCsv()
{
// open the file "data.csv" which is a CSV file with headers
using (CsvReader csv = new CsvReader(
new StreamReader("C:\\Users\\moki\\Downloads\\Input.csv"), true))
{
int fieldCount = csv.FieldCount;
string[] headers = csv.GetFieldHeaders();
while (csv.ReadNextRecord())
{
for (int i = 0; i < fieldCount; i++)
Console.WriteLine(string.Format("{0}\n{1}",
headers[0], csv[i]) );
}
}
Console.ReadLine();
my Result
Since we're providing answers...
using System;
using System.Collections.Generic;
using System.Linq;
namespace _51306985
{
class Program
{
static List<List<string>> listOfList = new List<List<string>>();
static int longestCol = 0;
static void Main(string[] args)
{
FillTheList("M:\\StackOverflowQuestionsAndAnswers\\51306985\\testdata.csv");
PadTheList();
SpitItBackOut();
SpitItOutToAFile("M:\\StackOverflowQuestionsAndAnswers\\51306985\\testdata.csv");
Console.ReadLine();
}
private static void SpitItOutToAFile(string v)
{
string newPath = $"{System.IO.Path.GetDirectoryName(v)}\\{System.IO.Path.GetFileNameWithoutExtension(v)}_Rotated{System.IO.Path.GetExtension(v)}";
using (System.IO.StreamWriter sw = new System.IO.StreamWriter(newPath))
{
for (int i = 0; i < longestCol; i++)
{
string lineToWrite = string.Empty;
for (int b = 0; b < listOfList.Count; b++)
{
lineToWrite += $"{listOfList[b][i]},";
}
lineToWrite = lineToWrite.Substring(0, lineToWrite.Length - 1);//remove the hanging comma
if (lineToWrite != "")
{
sw.WriteLine(lineToWrite);
}
}
}
}
private static void SpitItBackOut()
{
for (int i = 0; i < longestCol; i++)
{
string lineToWrite = string.Empty;
for (int b = 0; b < listOfList.Count; b++)
{
lineToWrite += $"{listOfList[b][i]},";
}
lineToWrite = lineToWrite.Substring(0, lineToWrite.Length - 1);//remove the hanging comma
if (lineToWrite != "")
{
Console.WriteLine(lineToWrite);
}
}
}
private static void PadTheList()
{
foreach (List<string> item in listOfList)
{
while (item.Count < longestCol)
{
item.Add("");
}
}
}
private static void FillTheList(string v)
{
using (System.IO.StreamReader sr = new System.IO.StreamReader(v))
{
string currentLine = string.Empty;
while ((currentLine = sr.ReadLine()) != null)
{
listOfList.Add(currentLine.Split(',').ToList());
if (listOfList.Last().Count > longestCol)
{
longestCol = listOfList.Last().Count;
}
}
}
}
}
}
Input Data
a1,b1,c1,d1,e1
a2,b2,c2,d2,e2
a3,b3,c3,d3,e3
a4,b4,c4,d4,e4
a5,b5,c5,d5,e5
a6,b6
a7,b7,c7,d7
a8,b8,c8
Output
a1,a2,a3,a4,a5,a6,a7,a8
b1,b2,b3,b4,b5,b6,b7,b8
c1,c2,c3,c4,c5,,c7,c8
d1,d2,d3,d4,d5,,d7,
e1,e2,e3,e4,e5,,,
There surely is a more efficient way but this is a easy to understand way I think:
1.) put the data into a datatable, e.g. like:
StreamReader sr1 = new StreamReader("C:\\Users\\moki\\Downloads\\Input.csv"); //create the streamreader to read the input .csv
DataTable mydata = new DataTable(); //create an empty DataTable.....
string[] arr; //....and an array in which you will store the elemnets of each line
int i = 0; //just a variable to help counting where you are in your data
bool mydatasetup = false; //a variable to check in the loop if you already added the necessary number of columns to the datatable
using (sr1)
{
while (sr1.EndOfStream == false) //read the whole file
{
string line = sr1.ReadLine(); //get a line from the file
if (line != null && line != String.Empty) //check if there is content in the line
{
arr = line.Split(';'); //split the line at each ";" and put the elements in the array
if(mydatasetup == false) //after reading the first line add as many columns to your datatable as you will need.....
{
for (int u = 0; u < arr.Length; u++)
{
mydata.Columns.Add();
}
mydatasetup = true; //...but only do this once (otherwise you wil have an unneccessary big datatable
}
mydata.Rows.Add(); //add a row in you datatable in which you will store the data of the line
for (int j = 0; j < arr.Length; j++) //go throught each element in your array and put it into your datatable
{
if (arr[j] != "")
{
mydata.Rows[i][j] = arr[j];
}
}
i = i + 1; //increase the counter so that the program knows it has to fill the data from the next line into the next row of the datatable
}
}
}
2.) Then you can loop through your datatable's columns and add each row's contents to a Stringbuilder (whereby you transpose your data) which you then save as a .csv:
StringBuilder sb = new StringBuilder(); //create a stringbuilder
for (int u = 0; u < mydata.Columns.Count; u++) //loop through the COLUMNS of your datatable....
{
for (int i = 0; i < mydata.Rows.Count; i++) //....but for each column go through each row in the datatable first
{
sb.Append(mydata.Rows[i][u].ToString()); // and add the elements to the stringbuilder - here the transposing is actually done
if (i < mydata.Rows.Count - 1) //add a deliminator after each element because you want a .csv as output again
{
sb.Append(';');
}
}
sb.AppendLine(); //add another line to your stringbuilder in which you will store the next column of your datatable
}
File.WriteAllText("C:\\Users\\moki\\Downloads\\Output.csv", sb.ToString()); //finally create the output .csv
You could of course combine these two steps.
Just in case, if anyone want to know how to do it using Cinchoo ETL with few lines of code,
string csv = #"A1;B1;C1;D1;E1
A2;B2;C2;D2;E2
A3;B3;C3;D3;E3
A4;B4;C4;D4;E4
A5;B5;C5;D5;E5
";
StringBuilder sb = new StringBuilder();
using (var p = ChoCSVReader.LoadText(csv)
.WithDelimiter(";")
.ThrowAndStopOnMissingField(false)
)
{
using (var w = new ChoCSVWriter(sb)
.WithDelimiter(";")
)
{
w.Write(p.Cast<ChoDynamicObject>().Transpose(false));
}
}
Console.WriteLine(sb.ToString());
Output:
A1;A2;A3;A4;A5
B1;B2;B3;B4;B5
C1;C2;C3;C4;C5
D1;D2;D3;D4;D5
E1;E2;E3;E4;E5
I'm using WinForms. In my form I have a listview and a button. When I click on the button the program writes all of the items in the listview into a text file. The problem is that I want the first and second column to be in one line.
Here is my code so far that i use to write to the text file:
using (StreamWriter sw = File.CreateText(DirectoryPath))
{
foreach (ListViewItem item in listView1.Items)
{
sw.WriteLine(item.Text);
for (int i = 1; i < item.SubItems.Count; i++)
{
sw.WriteLine(item.SubItems[i].Text);
}
}
}
My ListView
Problem output text file
How I want the text file to display
How about just
using (StreamWriter sw = File.CreateText(DirectoryPath))
{
foreach (ListViewItem item in listView1.Items)
{
sw.Write(item.Text + ": ");
for (int i = 1; i < item.SubItems.Count; i++)
{
sw.WriteLine(item.SubItems[i].Text);
}
}
}
It seems that your first cell "FirstPage" is the parent and all other items are sub items. Assuming you have only two columns below answer will work.
using (StreamWriter sw = File.CreateText(DirectoryPath))
{
foreach (ListViewItem item in listView1.Items)
{
sw.Write(string.Format("{0} :",item.Text));
for (int i = 1; i < item.SubItems.Count; i++)
{
if (i % 2 == 0)
{
sw.Write(string.Format("{0} :",item.SubItems[i].Text));
}
else
{
sw.WriteLine(item.SubItems[i].Text);
}
}
}
}
Alternative is; add each new row as a new item to the list view
string[] row = { "FirstPage", "$1.00" };
string[] row2 = { "SecondPage", "$1.00" };
var listViewItem = new ListViewItem(row);
listView1.Items.Add(listViewItem);
var listViewItem2 = new ListViewItem(row2);
listView1.Items.Add(listViewItem2);
and so on. You can iterate through a foreach loop for this adding and then use the below code which is flexible.
using (StreamWriter sw = File.CreateText(DirectoryPath))
{
foreach (ListViewItem item in listView1.Items)
{
sw.Write(string.Format("{0} :",item.Text));
for (int i = 1; i < item.SubItems.Count; i++)
{
sw.WriteLine(item.SubItems[i].Text);
}
}
}
You can do it in a more elegant way:
var str = listView1.Items.Cast<ListViewItem>()
.Select(x => x.SubItems.Cast<ListViewItem.ListViewSubItem>())
.Select(x => string.Join(":", x.Select(s => s.Text)));
System.IO.File.WriteAllLines(#"d:\file.txt", str);
Note: If you want to limit the columns for example save only first two columns, you can select sub items at second line this way: x.SubItems.Cast<ListViewItem.ListViewSubItem>().Take(2)
You should iterate the List View items, concatenate each one of the sub items into each other and then add the concatenated string to the text file at the end... I have adapted your code:
using (StreamWriter sw = File.CreateText(DirectoryPath))
{
foreach (ListViewItem item in listView1.Items)
{
string strText = "";
//I'm not sure why you start at 1 and not 0, anyway:
for (int i = 1; i < item.SubItems.Count; i++)
{
strText+= " " + item.SubItems[i].Text;
}
sw.WriteLine(strText);
}
}
I don't know how to get a result from for to use in the foreach loop.
My code like:
List<string> lstNameImage = new List<string>();
for (int i = 0; i < lstImgAdded.Items.Count; i++)
{
string imgPath = lstImgAdded.Items[i].SubItems[0].Text;
lstNameImage.Add(imgPath);
}
foreach (var items in lstNameImage)
{
Image img = Image.FromFile(items[0].ToString()); // how to using img in before for loop?
}
You can change the below line
string imgPath = lstImgAdded.Items[i].SubItems[getRows].Text;
To just
string imgPath = lstImgAdded[i];
In foreach item variable already contains the list item what you are trying to get and so passing item would suffice
foreach (var item in lstNameImage)
{
Image img = Image.FromFile(item);
}
This code:
foreach (var items in lstNameImage)
{
Image img = Image.FromFile(item);
}
is functionally equivalent to:
foreach (int index = 0; index < lstNameImage.Count; index++)
{
var item = lstNameImage[index];
Image img = Image.FromFile(item);
}
Hence Rahul's solution.
I have a checkedlistbox in which i am populating items like:
Biology+Physics+Chemistry
English+Urdu+Islamiyat
and so on. Now when i retrieve the values of selected items by splitting them on the basis of '+' sign, it gives me an output like:
Biology
Physics
ChemistryEnglish
Urdu
Islamiyat
Now you can look at the output as all values are right except ChemistryEnglish which have got concatenated. What should i be doing so to make this right? I want the output like this:
Biology
Physics
Chemistry
English
Urdu
Islamiyat
UPDATED
MY CODE IS:
String items = "";
string SQLString = "";
if (this.subjects_listbox.CheckedItems.Count != 0)
{
for (int i = 0; i < this.subjects_listbox.Items.Count; i++)
{
items += this.subjects_listbox.CheckedItems[i].ToString();
}
} //
String[] subNames = items.Split('+');
foreach (var item in subNames)
{
MessageBox.Show(item);
}
Finally i achieved my goal this by doing this:
String items = "";
string SQLString = "";
if (this.subjects_listbox.CheckedItems.Count != 0)
{
for (int i = 0; i < this.subjects_listbox.Items.Count; i++)
{
items += this.subjects_listbox.CheckedItems[i].ToString() + "+";
}
} //
String[] subNames = items.Split('+');
foreach (var item in subNames)
{
MessageBox.Show(item);
}
I think you need to split out the items in the CheckedListBox individually before you do what you are doing with items. Take the following code (assuming myCheckedListBox is the name of your CheckedListBox)
var subNameList = new List<string>();
foreach (var item in myCheckedListBox.Items)
{
foreach (string subName in (item.ToString().Split('+'))
{
subNameList.Add(subName);
}
}
This will result in you having a list of strings at the end in subNameList. You may want to use myCheckedListBox.CheckedItems rather than myCheckedListBox.Items depending on your use case.
I achieved my goal by doing this:
String items = "";
string SQLString = "";
if (this.subjects_listbox.CheckedItems.Count != 0)
{
for (int i = 0; i < this.subjects_listbox.Items.Count; i++)
{
items += this.subjects_listbox.CheckedItems[i].ToString() + "+";
}
}
String[] subNames = items.Split('+');
foreach (var item in subNames)
{
MessageBox.Show(item);
}
I am having trouble populating a datagridview with items from a string array. Here is the code I used to call the function:
ThreadPool.QueueUserWorkItem((o) =>
ReBuildObjectExplorer();
And the function itself:
try
{
List<ExplorerItem> list = new List<ExplorerItem>();
var item = new ExplorerItem();
for (int i = 0; i < lbl.Length; i++) // lbl = string array with items
{
item.title = lbl[i].Name;
list.Add(item);
}
BeginInvoke((MethodInvoker)delegate
{
explorerList = list;
dgvObjectExplorer.RowCount = explorerList.Count;
dgvObjectExplorer.Invalidate();
});
}
catch (Exception e) { MessageBox.Show(e.ToString(); }
The problem is: Suppose there are 76 items in the array. When I use this code, it ALWAYS adds the 75th item 76 times and nothing else. Why does this happen? I can't seem to figure out what is wrong with my code.
I think you want:
try
{
List<ExplorerItem> list = new List<ExplorerItem>();
for (int i = 0; i < lbl.Length; i++) // lbl = string array with items
{
var item = new ExplorerItem();
item.title = lbl[i].Name;
list.Add(item);
}
BeginInvoke((MethodInvoker)delegate
{
explorerList = list;
dgvObjectExplorer.RowCount = explorerList.Count;
dgvObjectExplorer.Invalidate();
});
}
catch (Exception e) { MessageBox.Show(e.ToString(); }
That is, move the creation of the new ExplorerItem inside the loop rather than outside it. That way a new item is created at each iteration of the loop. If you don't create a new item in each iteration, then you are adding the same item over and over again, changing its title in every iteration.