Find the maximum length of every column in a csv file - c#

So, I was trying to present a csv document in a console application. However, due to the varying text size in it, the output was not in a presentable format.
To present it, I tried to count the maximum length of text for each column and then append white space to the remaining text in that column so that there's equal length of characters in each column.
I tried to get the character count, but can't seem to figure out how to proceed further.
var file = File.ReadAllLines(#"E:\File.csv");
var lineList = file.Select(x => x.Split(',').ToList()).ToList();
int maxColumn = lineList.Select(x => x.Count).Max(x => x);
List<int> maxElementSize = new List<int>();
for (int i = 0; i < maxColumn; i++)
{
//Some Logic
}
Any help would be highly appreciated.

Here's a sample console application to get maximum character length for each column :
static void Main(string[] args)
{
string CSVPath = #"D:\test.csv";
string outputText = "";
using (var reader = File.OpenText(CSVPath))
{
outputText = reader.ReadToEnd();
}
var colSplitter = ',';
var rowSplitter = new char[] { '\n' };
var rows = (from row in outputText.Split(rowSplitter, StringSplitOptions.RemoveEmptyEntries)
let cols = row.Split(colSplitter)
from col in cols
select new { totalCols = cols.Count(), cols = cols }).ToList();
int[] maxColLengths = new int[rows.Max(o => o.totalCols)];
for (int i = 0; i < rows.Count; i++)
{
for (int j = 0; j < rows[i].cols.Count(); j++)
{
int curLength = rows[i].cols[j].Trim().Length;
if (curLength > maxColLengths[j])
maxColLengths[j] = curLength;
}
}
Console.WriteLine(string.Join(", ", maxColLengths));
}
Hope this helped.

Try with a nested for loop:
var inputLines = File.ReadAllLines(#"E:\File.csv");
Dictionary<int,int> dictIndexLenght = new Dictionary<int,int>();
foreach(var line in inputLines)
{
List<string> columList = line.Split(',').ToList();
for (int i = 0; i < columList.Count; i++)
{
int tempVal = 0;
if(dictIndexLenght.TryGetValue(i,out tempVal))
{
if(tempVal<columList[i].Length)
{
dictIndexLenght[i]=columList[i].Length;
}
}
else
dictIndexLenght[i]=columList[i].Length;
}
}
Can check the result here or with this lines of code:
for(int i=0;i<dictIndexLenght.Count;i++)
{
Console.WriteLine("Column {0} : {1}", i, dictIndexLenght[i]);
}

Here's how I would do it, very similar to un-lucky's answer, only using a List<int> instead of a Dictionary<int, int>. I added dummy data for testing, but you can see the actual call to read the file is left in there, so you can just remove the dummy data and the line that reads it, and it should work ok:
static void Main(string[] args)
{
var fileLines = new List<string>
{
"Lorem, Ipsum, is, simply, dummy, text, of, the, printing, and, typesetting,",
"industry., Lorem, Ipsum, has, been, the, industry's, standard, dummy, text,",
"ever, since, the, 1500s, when, an, ",
"unknown, printer, took, a, galley, of, type, and, scrambled, it, to, make,",
"a, type, specimen, book.,",
"It, has, survived, not, only, five, centuries, but, also, the, leap,",
"into, electronic, typesetting, remaining, essentially, unchanged.,",
"It, was, popularised, in, the, 1960s, with, the, release,",
"of, Letraset, sheets, containing, Lorem, Ipsum, passages, and, more, ",
"recently, with, desktop, publishing,",
"software, like, Aldus, PageMaker, including, versions, of, Lorem, Ipsum."
};
var filePath = #"f:\public\temp\temp.csv";
var fileLinesColumns = File.ReadAllLines(filePath).Select(line => line.Split(','));
var colWidths = new List<int>();
// Remove this line to use file data
fileLinesColumns = fileLines.Select(line => line.Split(','));
// Get the max length of each column and add it to our list
foreach (var fileLineColumns in fileLinesColumns)
{
for (int i = 0; i < fileLineColumns.Length; i++)
{
if (i > colWidths.Count - 1)
{
colWidths.Add(fileLineColumns[i].Length);
}
else if (fileLineColumns[i].Length > colWidths[i])
{
colWidths[i] = fileLineColumns[i].Length;
}
}
}
// Write out our columns, padding each one to match the longest line
foreach (var fileLineColumns in fileLinesColumns)
{
for (int i = 0; i < fileLineColumns.Length; i++)
{
Console.Write(fileLineColumns[i].PadRight(colWidths[i]));
}
Console.WriteLine();
}
Console.Write("\nDone!\nPress any key to exit...");
Console.ReadKey();
}
Output

Initialise your list, then loop over your lines, and within that line, loop over your columns:
for (i = 0; i < lineList.Count; i++)
{
maxElementSize[i] = 0;
}
for (i = 0; i < lineList.Count; i++)
{
for (j = 0; j < maxColumn; j++)
{
if(lineList[i][j].Length > maxElementSize[j])
maxElementSize[j] = lineList[i][j].Length
}
}

I use the following code to make sure the columns in a database are large enough to take the csv input data...
#!/usr/bin/python3
import array as arr
from csv import reader
import argparse
def csv_getFldLens (in_file, has_header=0, delimiter=','):
# open file in read mode
fldMaxLens = arr.array('i')
headers = []
has_header = has_header
with open(in_file, 'r') as read_obj:
# pass the file object to reader() to get the reader object
csv_reader = reader(read_obj, delimiter=delimiter)
# Iterate over each row in the csv using reader object
rcnt = 0
lastIndx = 0
for row in csv_reader:
# row variable is a list that represents a row in csv
# print(row)
if has_header and rcnt == 0:
for fld in row:
headers.append(fld)
rcnt += 1
continue
j = 0
for fld in row:
fldLen = len(fld)
if (lastIndx == 0) or (lastIndx < j):
# print("if --- li, i: ", lastIndx, i, "\n")
fldMaxLens.append(fldLen)
lastIndx = j
else:
# print("else --- li, i: ", lastIndx, i, "\n")
v1 = fldMaxLens[j]
v2 = fldLen
fldMaxLens[j] = max(v1,v2)
j = j + 1
rcnt += 1
j = 0
if has_header:
for f in headers:
print(f,": ", fldMaxLens[j])
j += 1
else:
for i in fldMaxLens:
print("Col[",j+1,"]: ",fldMaxLens[j])
j += 1
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Get column lengths of CVS fields.')
parser.add_argument('--in_file', default='', help='The CSV input file')
parser.add_argument('--has_header', action='store_true', help='The CSV file has headers')
parser.add_argument('--delimiter', default=',', help='Sets the delimiter. Default is comma \',\'.')
args = parser.parse_args()
csv_getFldLens(in_file=args.in_file, has_header=args.has_header, delimiter=args.delimiter)

Related

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]);
}
}

trouble reading and writing to a file c#

I am currently trying to take a file of words that are not in alphabetical, re-order the words so that they are in alphabetical order (I am trying to use a non-built in sort method), and then write the newly ordered list into a new txt file(one that must be created). For example, lets say there is only five words in the txt file that are as follows "dog bat apple rabbit cat". I would want the program to resort these in alphabetical order, and then create a txt file that saves that order. As of right now, the program will iterate through the txt file, but will not save the re-ordered list into the new txt file. What is saved into the new file is this... "System.Collections.Generic.List`1[System.String]"
Truth be told, I am not very savvy with c# yet, so i apologize if my structuring or coding is not very well. The original file that is un-ordered is called "jumbled english FILTERED.ALL.txt", and the file I am trying to write to is called "english FILTERED.ALL.txt".
static void Main(string[] args)
{
// declaring integer for minimum.
int min = 0;
// declare the list for the original file
List<string> LinuxWords = new List<string>();
List<string> lexicalOrder = new List<string>();
// read the text from the file
string[] lines = System.IO.File.ReadAllLines("jumbled english FILTERED.ALL.txt");
string line = string.Empty;
// seperate each word into a string
//foreach (string line in lines)
//{
//add each word into the list.
//LinuxWords.Add(line);
//}
for (int i = 0; i < lines.Length - 1; i++)
{
for (int j = i + 1; j < lines.Length; j++)
{
if (lines[i].Length < lines[j].Length)
{
min = lines[i].Length;
}
else
{
min = lines[j].Length;
}
for (int k = 0; k < min; k++)
{
if (lines[i][k] > lines[j][k])
{
line = lines[i].ToString();
lines[i] = lines[j];
lines[j] = line;
break;
}
else if (lines[i][k] == lines[j][k])
{
continue;
}
else
{
break;
}
}
}
}
for (int i = 0; i < lines.Length; i++)
{
Console.WriteLine("The program is formatting the correct order");
lexicalOrder.Add(lines[i]);
}
//lexicalOrder.ForEach(Console.WriteLine);
//}
//LinuxWords.ForEach(Console.WriteLine);
File.WriteAllText(AppDomain.CurrentDomain.BaseDirectory + "english FILTERED.ALL.txt",
lexicalOrder.ToString());
// write the ordered list back into another .txt file named "english FILTERED.ALL.txt"
// System.IO.File.WriteAllLines("english FILTERED.ALL.txt", lexicalOrder);
Console.WriteLine("Finished");
}
Assuming you mean that you don't get the list saved (if that's not the problem - please be more specific) - you need to change
lexicalOrder.ToString()
to something like
lexicalOrder.Aggregate((s1, s2) => s1 + " " + s2)

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.

name is not incrementing by 1 after number 45

i am trying to add a location name to my output text files.
As you can see my numbers are incrementing properly. But i have coded like after number 45 i need to reset the number to 1, also the Carousel:45 should change to ** Carousel1:1**. But it is not happening... why it is not happening. any help please!!!!
My code snippet:
public void just_create_text()
{
//Here we are exporting header
string[] strLines = System.IO.File.ReadAllLines(textBox1.Text);
string CarouselName = enter.Text;
int[] cols = new int[] { 15, 15, 25, 15, 15 };
StringBuilder sb = new StringBuilder();
string line = RemoveWhiteSpace(strLines[0]).Trim();
string[] cells = line.Replace("\"", "").Split('\t');
for (int c = 0; c < cells.Length; c++)
sb.Append(cells[c].Replace(" ", "_").PadRight(cols[c]));
sb.AppendLine("Location".PadRight(15));
sb.AppendLine();
int tmpCarousel = 0;
int carouselNumber = 0;
Dictionary<string, int> namesForCarousels = new Dictionary<string, int>();
for (int i = 0; i < textfile.Count; i++)
{
for (int c = 0; c < cells.Length; c++)
sb.Append(textfile[i].Cells[c].Replace(" ", "_").PadRight(cols[c]));
string name = textfile[i].Cells[1];
if (namesForCarousels.TryGetValue(name, out tmpCarousel) == false)
{
carouselNumber++;
if (carouselNumber > 45)
carouselNumber = 1;//resetting to number1, but name is
//not changing to Carousel1..
namesForCarousels[name] = carouselNumber;
}
var strCorousel = lstMX.Find(x => x.MAX_PN.Equals(name)).Carousel;
strCorousel = (String.IsNullOrEmpty(strCorousel)) ? CarouselName : strCorousel;
sb.Append(String.Format("{0}:{1}", strCorousel, carouselNumber).PadRight(15));
sb.Append("\r\n");
}
System.IO.File.WriteAllText(#"Z:\Desktop\output.TXT", sb.ToString());
}
OUTPUT i need
I need after Carousel:45 >>> i need Carousel1:1. How can i do this..?
You never use the numbers stored in your dictionary namesForCarousels after setting them. Probably you want
sb.Append(String.Format("{0}:{1}", strCorousel, namesForCarousels[name]).PadRight(15));
Also, you should rename carouselNumber to something like carouselNumberCounter. It's not the number of the current carousel, it's a counter used to assign a number to the next carousel. And for additional clarity, get rid of the local variable tmpCarousel and do:
if (!namesForCarousels.ContainsKey(name))
{
You might find it easier to follow your code if you use more descriptive variable names. It's not entirely clear what you're trying to do, but I assume you want to re-use the same carousel number for a given "Max Pn" if you've already allocated it - at the moment, you populate that mapping but you don't use it, you are reliant on max pn being in order. I don't actually see why carousel number wouldn't reset, but if you tidy it up perhaps you have a better chance of seeing what is happening.
Also given your null reference exception from your other question, this protects against that - though it probably indicates another problem elsewhere in the population of your "lstMx".
public static void just_create_text()
{
//Here we are exporting header
string[] strLines = System.IO.File.ReadAllLines(textBox1.Text);
string defaultCarouselName = enter.Text;
int[] columnPaddings = new int[] { 15, 15, 25, 15, 15 };
StringBuilder completedOutputBuilder = new StringBuilder();
string line = RemoveWhiteSpace(strLines[0]).Trim();
string[] cells = line.Replace("\"", "").Split('\t');
for (int c = 0; c < cells.Length; c++)
completedOutputBuilder.Append(cells[c].Replace(" ", "_").PadRight(columnPaddings[c]));
completedOutputBuilder.AppendLine("Location".PadRight(15));
completedOutputBuilder.AppendLine();
int carouselNumberForEntry = 0;
Dictionary<string, int> maxPnToCarouselNumber = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
for (int i = 0; i < textfile.Count; i++)
{
for (int c = 0; c < cells.Length; c++)
completedOutputBuilder.Append(_textfile[i].Cells[c].Replace(" ", "_").PadRight(columnPaddings[c]));
string maxPnForEntry = textfile[i].Cells[1];
int previouslyAllocatedCarouselNumberForMaxPn = 0;
if (maxPnToCarouselNumber.TryGetValue(maxPnForEntry, out previouslyAllocatedCarouselNumberForMaxPn) == false)
{
// assign a new courousel number for this max pn
carouselNumberForEntry++;
if (carouselNumberForEntry > 45)
carouselNumberForEntry = 1;
// for better clarity use add
maxPnToCarouselNumber.Add(maxPnForEntry, carouselNumberForEntry);
}
else
{
// use the carousel number previous assigned for this maxPn
carouselNumberForEntry = previouslyAllocatedCarouselNumberForMaxPn;
}
// find the related max pn carousel entry (if relatedPn is not found this suggests a problem elsewhere)
MAX_PN_Carousel relatedPn = lstMx.Find(x => x.MAX_PN != null && x.MAX_PN.Equals(maxPnForEntry, StringComparison.OrdinalIgnoreCase));
// assign the name from the entry, or use the default carousel name if unavailable
string carouselNameForMaxPn = (relatedPn == null || String.IsNullOrWhiteSpace(relatedPn.Carousel)) ? defaultCarouselName : relatedPn.Carousel;
// add the new column in the output
completedOutputBuilder.Append(String.Format("{0}:{1}", carouselNameForMaxPn, carouselNumberForEntry).PadRight(15));
completedOutputBuilder.Append("\r\n");
}
System.IO.File.WriteAllText(#"c:\dev\output.TXT", completedOutputBuilder.ToString());
}

How to implement C# code for Order id separated by commas and range separated by hyphens, and display all info of order

Ex: 1,4-90, 292,123
It needs to display the whole order information of
1
4,5,6....90
292
123.
Whats the gud approach to solve this.
It is similar to tracking in UPS or fedex if multiple orders are given in search box.
I meant if in a search box I giv 1,4-90, 292,123 this string the result that needs to come back is a grid representation of all the data which is corresponding to each of the order id respectively. I want to know how to parse the string into collection and send them to the database and show the information in the grid for...
1
4,5,6....90
292
123.
as a different row...from where I can generate reports too (alternative)
Please try.
static ArrayList list;
static void Main(string[] args)
{
string str = "1,4-90,292,123";
string[] arr = str.Split(',');
list = new ArrayList();
for (int i = 0; i < arr.Length; i++)
{
string tmp = arr[i];
if (tmp.IndexOf('-') != -1)
{
Range(tmp);
}
else list.Add(int.Parse(tmp));
}
list.Sort();
object[] intResult = list.ToArray();
//print the final result
for (int i = 0; i < intResult.Length; i++)
{
Console.WriteLine(intResult[i].ToString());
}
Console.Read();
}
static void Range(string range)
{
string[] tmpArr = range.Split('-');
int stInt = int.Parse(tmpArr[0]);
int edInt = int.Parse(tmpArr[1]);
int[] intArr = new int[(edInt - stInt) + 1];
for (int i = 0; stInt <= edInt; i++)
{
list.Add(stInt++);
}
}

Categories

Resources