Splitting an array into 2 parts - c#

I am attempting to read a log file in this format:
date | cost
date | cost
..ect
Using the following code to read the file in to an array:
string[] lines = File.ReadAllLines("log.txt");
My question is how do I slice the array in to 2 parts per line so that I can add them to a list view of 2 columns? I was thinking perhaps a dictionary would be a good start..

Assuming this is C# rather than C, the following may do what you're looking for:
public class LogEntry{
public string Date;
public string Cost;
public LogEntry(string date,string cost){
Date=date;
Cost=cost;
}
}
...
// Grab the lines from the file:
string[] lines = File.ReadAllLines("log.txt");
// Create our output set:
LogEntry[] logEntries=new LogEntry[lines.Length];
// For each line in the file:
for(int i=0;i<lines.Length;i++){
// Split the line:
string[] linePieces=lines[i].Split('|');
// Safety check - make sure this is a line we want:
if(linePieces.Length!=2){
// No thanks!
continue;
}
// Create the entry:
logEntries[i]=new LogEntry( linePieces[0] , linePieces[1] );
}
// Do something with logEntries.
Note that this sort of processing should only be done with a relatively small log file. File.ReadAllLines("log.txt") becomes very inefficient with large files, at which point using a raw FileStream is more suitable.

var lines = File.ReadAllLines("log.txt").Select(l=> l.Split('|'));
var dictionary= lines.ToDictionary(x => x[0], y => y[1]);

Use a 2D array and string.Split('-')
string[] lines = File.ReadAllLines("log.txt");
//Create an array with lines.Length rows and 2 columns
string[,] table = new string[lines.Length,2];
for (int i = 0; i < lines.Length; i++)
{
//Split the line in 2 with the | character
string[] parts = lines[i].Split('|');
//Store them in the array, trimming the spaces off
table[i,0] = parts[0].Trim();
table[i,1] = parts[1].Trim();
}
Now you will have an array that looks like this:
table[date, cost]
You could use a dictionary so you only have to look up the date if you want to improve it. EDIT: As #Damith has done
Additionally, with LINQ you could simplify this into:
var table = File.ReadAllLines("log.txt").Select(s => s.Split('|')).ToDictionary(k => k[0].TrimEnd(' '), v => v[1].TrimStart(' '));
Which you can now easily get the results from the LINQ expression with:
foreach (KeyValuePair<string, string> kv in table)
{
Console.WriteLine("Key: " + kv.Key + " Value: " + kv.Value);
}
Also note if you do not need the spaces in your file you can omit the Trim()s

And just because this post was originally tagged C :)
Here is a C example:
With a data file (I called it temp.txt) that looks like this:
3/13/56 | 13.34
3/14/56 | 14.14
3/15/56 | 15.00
3/16/56 | 16.56
3/17/56 | 17.87
3/18/56 | 18.34
3/19/56 | 19.31
3/20/56 | 20.01
3/21/56 | 21.00
This code will read it, parse it into a single 2 dim string array, char col[2][80][20];
#include <ansi_c.h>
int main()
{
int i;
char *buf;
char line[260];
char col[2][80][20];
FILE *fp;
fp = fopen("c:\\dev\\play\\temp.txt", "r");
i=-1;
while(fgets(line, 260, fp))
{
i++;
buf = strtok(line, "|");
if(buf) strcpy(col[0][i], buf);
buf = strtok(NULL, "|");
if(buf) strcpy(col[1][i], buf);
}
fclose(fp);
return 0;
}

Related

How to remove pieces of data from string

I have a text file with multiple entries of this format:
Page: 1 of 1
Report Date: January 15 2018
Mr. Gerald M. Abridge ID #: 0000008 1 Route 81 Mr. Gerald Michael Abridge Pittaburgh PA 15668 SSN: XXX-XX-XXXX
Birthdate: 01/00/1998 Sex: M
COURSE Course Title CRD GRD GRDPT COURSE Course Title CRD GRD GRDPT
FALL 2017 (08/28/2017 to 12/14/2017) CS102F FUND. OF IT & COMPUTING 4.00 A 16.00 CS110 C++ PROGRAMMING I 3.00 A- 11.10 EL102 LANGUAGE AND RHETORIC 3.00 B+ 9.90 MA109 CALC WITH APPLICATIONS I 4.00 A 16.00 SP203 INTERMEDIATE SPANISH I 3.00 A 12.00
EHRS QHRS QPTS GPA Term 17.00 17.00 65.00 3.824 Cum 17.00 17.00 65.00 3.824
Current Program(s): Bachelor of Science in Computer Science
End of official record.
So far, I have read the text file into a string, full. I want to be able to remove first two lines of each of the entries. How would I go about doing this?
Here's the code that I used to read it in:
using (StreamReader sr = new StreamReader(fileName, Encoding.Default))
{
string full = sr.ReadToEnd();
}
If all the lines you want to skip begin with the same strings, you can put those prefixes in a list and then, when you're reading the lines, skip the any that being with one of the prefixes:
This will leave you with a list of strings that represent all the file lines that don't begin with one of the specified prefixes:
var filePath = #"f:\public\temp\temp.txt";
var ignorePrefixes = new List<string> {"Page:", "Report Date:"};
var filteredContent = File.ReadAllLines(filePath)
.Where(line => ignorePrefixes.All(prefix => !line.StartsWith(prefix)))
.ToList();
If you want all the content as a single string, you can use String.Join:
var filteredAsString = string.Join(Environment.NewLine, filteredContent);
If Linq isn't your thing, or you don't understand what it's doing, here's the "old school" way of doing the same thing:
List<string> filtered = new List<string>();
foreach (string line in File.ReadLines(filePath))
{
bool okToAdd = true;
foreach (string prefix in ignorePrefixes)
{
if (line.StartsWith(prefix))
{
okToAdd = false;
break;
}
}
if (okToAdd)
{
filtered.Add(line);
}
}
public static IEnumerable<string> ReadReportFile(FileInfo file)
{
var line = String.Empty;
var page = "Page:";
var date = "Report Date:";
using(var reader = File.OpenText(file.FullName))
while((line = reader.ReadLine()) != null)
while(line.IndexOf(page) == -1 AND line.IndexOf(date) == -1)
yield return line;
}
Code is pretty straight forward, while line is not null and doesn't contain page or date, return line. You could condense or even get fancier, building lookups for your prefix etc. but if the code is simple or not needed to be that complex, this should suffice.

Edit specific word in specific line

I know this has been asked a few times, but I'm need a fast way to do this in files with different size (small and large files).
I need to edit scale factor in sat(txt) file. This is a first number in third line:
700 104 1 0 16 Autodesk AutoCAD 19 ASM 221.0.0.1871 NT 24 Tue
Aug 16 09:02:14 2016
1000 9.9999999999999995e-007 1e-010
I suggest extracting a method and Linq:
private static String MyEditLine(string value) {
var items = value.Split(new char[] { ' ' }, 2);
items[0] = "2000"; // let's change 1000 into 2000
return string.Join(" ", items);
}
...
var target = File
.ReadLines(#"C:\MyFile.txt")
.Select((line, index) => index != 2
? line
: MyEditLine(line))
.ToList();
File.WriteAllLines(#"C:\MyFile.txt", target);
assume you read your file and get a String[] called file and the number, you want to modify, is represented as float.
Than you can use the following code to first extract the line, you want. After this you get the number through float.TryParse(..)
int lineWithParam = 3;
String[] splittedLine = (file[lineWithParam-1]).Split(new char[] { ' ' }, 2);
if(splittedLine.Length == 2)
{
float fact = 0.0f;
String newFact = splittedLine[0];
// or how ever you want to modify your factor
if(float.TryParse(splittedLine[0], out fact))
{
newFact = "" + (fact * 12.3f);
}
file[lineWithParam-1] = newFact + " " + splittedLine[1];
}
Here an executable example: https://dotnetfiddle.net/NVgETo
after this you can write the String[] file back to the real file.
Note: this will not modify the file, if in the given line the first parameter isn't a valid float!

How to generate all possible words

I'm new to programming (C#).
The application is a 'words generator'.
What I'm looking for is a for loop that can generate all possible words with the characters in a given array of characters.
The details:
I have a List<char> = { A,a,6,w,# } (The length may vary)
I want to generate all possible words (for example: 4 letters length ) with this character set. This options should generate 5 characters & 4 letters = 5*5*5*5 = 625 words.
All generated words should be every possible combination of the given letters only
NOTE:
Some might tell me that i should use a solution called (Permutations of a String/Integer)
this method seems to be fine if the required words length is same as given characters length, but in my case i might give the application 100 characters, But i want it to generate all possible words -> 4 letters length (Example: MaRk, M#rK,m4rK...)
You could use an IEnumerable<String> method:
public IEnumerable<String> GenerateStrings (IEnumerable<char> characters, int length) {
if(length > 0) {
foreach(char c in characters) {
foreach(String suffix in GenerateStrings(characters,length-1)) {
yield return c+suffix;
}
}
} else {
yield return string.Empty;
}
}
Result with csharp (interactive C# shell):
csharp> Foo.GenerateStrings(new char[] {'A','a','6','w','#'},3)
{ "AAA", "AAa", "AA6", "AAw", "AA#", "AaA", "Aaa", "Aa6", "Aaw", "Aa#", "A6A", "A6a", "A66", "A6w", "A6#", "AwA", "Awa", "Aw6", "Aww", "Aw#", "A#A", "A#a", "A#6", "A#w", "A##", "aAA", "aAa", "aA6", "aAw", "aA#", "aaA", "aaa", "aa6", "aaw", "aa#", "a6A", "a6a", "a66", "a6w", "a6#", "awA", "awa", "aw6", "aww", "aw#", "a#A", "a#a", "a#6", "a#w", "a##", "6AA", "6Aa", "6A6", "6Aw", "6A#", "6aA", "6aa", "6a6", "6aw", "6a#", "66A", "66a", "666", "66w", "66#", "6wA", "6wa", "6w6", "6ww", "6w#", "6#A", "6#a", "6#6", "6#w", "6##", "wAA", "wAa", "wA6", "wAw", "wA#", "waA", "waa", "wa6", "waw", "wa#", "w6A", "w6a", "w66", "w6w", "w6#", "wwA", "wwa", "ww6", "www", "ww#", "w#A", "w#a", "w#6", "w#w", "w##", "#AA", "#Aa", "#A6", "#Aw", "#A#", "#aA", "#aa", "#a6", "#aw", "#a#", "#6A", "#6a", "#66", "#6w", "#6#", "#wA", "#wa", "#w6", "#ww", "#w#", "##A", "##a", "##6", "##w", "###" }
The advantage of using a method with a yield statement is that it is lazy: if you only need five such strings, not all possible strings will be generated first...
Willem Van Onsem, thanks! This was exactly what i've been looking for. But my problem sounds little different. I have to generate all possible strings without repetition of chars from source array. And here is your code, that i modified to do so:
public static IEnumerable<string> GenerateStrings(IEnumerable<char> characters, int length, int count)
{
if (length > 0)
{
foreach (char c in characters)
{
char[] charactersDec = new char[characters.Count()];
Array.Copy(characters.ToArray(), charactersDec, characters.Count());
int index = Array.IndexOf(charactersDec, c);
charactersDec = charactersDec.Where((val, idx) => idx != index).ToArray();
foreach (string suffix in GenerateStrings(charactersDec, length - 1, count++))
{
yield return c + suffix;
}
}
}
else
{
yield return string.Empty;
}
}
I remove current char from array and passed this array to recursive call.
output for a, b, c, d will be:
ab
ba
ac
ca
ad
da
bc
cb
bd
db
cd
dc
please, sorry my english.

How to parse delimited files to be compared

There is a text file formatted like the example below that I need to search for a students class name:
Michael | Straham | Eng101(4.0) | Mth303
Jacob | Black | SCI 210 (2.3) | Eng101
Ian | Summers | Mth303(3.30) | Sci 210
The delimited symbols are ( | )
The class names are "ENG101, SCI210, MTH303." I would like to search each line from the text for that class name and somehow index them so that they can be compared. The end result would be this:
ENG101:
Michael Straham, Jacob Black
Please assist. Thanks in advance!
I'm assuming you're already reading in the input line by line.
You can use String.Split() to accomplish (the first part of) what you are trying to do.
For example, the following code
String s1 = "Michael | Straham | Eng101(4.0) | Mth303";
char[] separators = { '|' };
String[] values = s1.Split(separators);
would give you an array of 4 strings ( "Michael", "Straham", "Eng101(4.0)", "Mth303"). You can then analyze the values array to see who is in which class. I'd probably have code roughly that looks like this (in pseudocode):
foreach (line in input)
{
String s1 = line;
char[] separators = { '|' };
String[] values = s1.Split(separators);
String firstName = values[0];
String lastName = values[1];
for (i = 2, i < values.length)
{
if (values[i] looks like "ENG101")
{
add firstName lastName to "ENG101" student list
}
else if (values[i] looks like "MTH303")
{
....
}
....
}
}

C# Crashing if no input for string Array

I Have a string array with 5 values, i want the program to loop even though i don't enter a value for the arrays. If I split the arrays without inserting anything (pressing ..... (5 times "." to split the array) then it doesn't crash it will just loop. But if i just hit enter, then the program crashes.
Is there a way to fix the loop so that even though there is no kind of input, that it won't crash? (It also crashes if you don't complete all 5 values.)
Net = Console.ReadLine();
string[] oktet = new string[5];
oktet = Net.Split('.', '/');
temp = oktet[0]; //inputs value of array in temp
NaN = int.TryParse(temp, out Net0);
temp = oktet[1];
NaN = int.TryParse(temp, out Net1);
temp = oktet[2];
NaN = int.TryParse(temp, out Net2);
temp = oktet[3];
NaN = int.TryParse(temp, out Net3);
temp = oktet[4];
NaN = int.TryParse(temp, out subnet);
}
while (!NaN | Net0 > 255 | Net0 < 0 | Net1 > 255 | Net1 < 0 | Net2 > 255 | Net2 < 0 | Net3 > 255 | Net3 < 0 | subnet > 32 | subnet < 0);
I know it's pretty amateur, but hey, we're here to learn right? :)
Thanks in advanced!
You can try to do something like this:
string[] oktet = Net.Split('.', '/'); // size array according to input
if (oktet.Length != 5) continue; // reloop on bad input
Those two lines of code replace these:
string[] oktet = new string[5];
oktet = Net.Split('.', '/');
I would just use some command line option library if you could (unless this is homework where you need to learn how to validate input, parse, etc.). See NDesk.Options (http://www.ndesk.org/Options), available via Nuget as well. See the following for required options: How to enforce required command-line options with NDesk.Options?
var userInput = Console.ReadLine();
var userInputSplit = userInput.Split('.', '/');
var numbers = userInputSplit.Select(word =>
{
int result;
if (byte.TryParse(word, out result))
return (byte?)result;
return (byte?)null; });
});
var inputComplete = number.Where(number => number.HasValue).Count() == 4;
The problem is that your variable oktet isn't an array of 5, because you're assigning something else in it.
string[] oktet = new string[5]; // Assigns an array of 5
oktet = Net.Split('.', '/'); //assigns the result of the split to the variable
So, oktet is has the result of the split, and its length.
BTW, Classes start with a capital letter, and the variables should start with a small letter.
Coding standards will make the code more readable, and will help you tell the difference between items.

Categories

Resources