Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 days ago.
Improve this question
I have this method, where i load data from csv file
public static List<string> LoadStations()
{
using (StreamReader reader = new StreamReader(#"X:\2022-23\ZPR\GDI Jízní řád\jizdniradgdi\Stations.csv"))
{
List<string> stations = new List<string>();
while (!reader.EndOfStream)
{
string line = reader.ReadLine();
string[] values = line.Split(new char[] { ';' }, 1);
values[0] = values[0].Trim();
foreach (var item in values)
{
stations.Add(item);
}
}
return stations;
}
}
How can i work with the data in the list somewhere else?
For example if i want to write them in console, but not in the method?
How can i work with the data in the list somewhere else?
You call the method:
var stations = LoadStations();
Now the variable stations will refer to the list. You could do something like this to write out the contents:
var stations = LoadStations();
foreach(var station in stations)
{
Console.WriteLine(station);
}
But this doesn't seem right. If you have a file with 3 columns and 4 rows, you're gonna end up with a list that has 3 single items. It throws away the rest of the data. That seems like a recipe for duplicating work later on.
Instead, I recommend starting from code more like this:
public static IEnumerable<string[]> LoadStations(string fileName)
{
var lines = File.ReadLines(fileName);
return lines.Select(line => line.Split(';'));
}
This returns all the columns. It does skip the .Trim() call, but we can put that back:
public static IEnumerable<string[]> LoadStations(string fileName)
{
var lines = File.ReadLines(fileName);
return lines.Select(line => line.Split(';').Select(c => c.Trim()).ToArray());
}
Then you can use it like this:
var stations = LoadStations(#"X:\2022-23\ZPR\GDI Jízní řád\jizdniradgdi\Stations.csv");
foreach(var station in stations)
{
Console.WriteLine(station[0]);
}
Notice this doesn't even use a list. Instead, it uses an IEnumerable. The advantage is this means you only need to keep one line in memory at a time, but it was still easy to use with a foreach loop.
Even better: Convert the string array into a class with proper field or property names. This will save you so much work needing to reparse the same data later on.
public static IEnumerable<Station> LoadStations(string fileName)
{
var lines = File.ReadLines(fileName);
return lines.Select(line => new Station() {
Name = line[0].Trim(),
OtherField = line[1].Trim(),
IntegerField = int.Parse(line[2].Trim()),
Etc = line[N].Trim()
});
}
var stations = LoadStations(#"X:\2022-23\ZPR\GDI Jízní řád\jizdniradgdi\Stations.csv");
foreach(var station in stations)
{
Console.WriteLine(station.Name);
}
Even better: Use a dedicated CSV parser! There are just so many edge cases around CSV data. We think it's simple, and a given file usually is. But more broadly you will tend towards better performance and consistency pulling a real CSV parser from NuGet.
I have my json ["[\"~:bbl:P5085\",\"~:cosco:NoTag\"]"] coming in
options.Type1.Values()
I am trying to keep only the values coming with bbl so from above I want to keep P5085 and remove all, there can be multiple bbl values in here and I need to keep all. I tried the below code but its not working. The splitting gives me
P5085","~:cosco
I dont understand what wrong am i doing in below code. Can someone provide the fix here?
private void InitializePayload(JsonTranslatorOptions options)
{
_payload.Add("ubsub:attributes", _attributes);
_payload.Add("ubsub:relations", _relations);
JArray newType = new JArray();
foreach (JValue elem in options.Type1.Values())
{
if (elem.ToString().Contains("rdl"))
{
string val = elem.ToString().Split(":")[1];
newType.Add(val);
}
}
_payload.Add("ubsub:type", newType);
}
Try this:
var input = "['[\"~:bbl:P5085\",\"~:cosco:NoTag\"]']";
var BBLs_List = JArray.Parse(input)
.SelectMany(m => JArray.Parse(m.ToString()))
.Select(s => s.ToString().Split(":"))
.Where(w => w[1] == "bbl")
.Select(s => s[2])
.ToList();
As I explain in the comments this isn't JSON, except at the top level which is an array with a single string value. That specific string could be parsed as a JSON array itself, but its values can't be handled as JSON in any way. They're just strings.
While you could try parsing and splitting that string, it would be a lot safer to find the actual specification of that format and write a parser for it. Or find a library for that API.
You could use the following code for parsing, but it's slow, not very readable and based on assumptions that can easily break - what happens if a value contains a colon?
foreach(var longString in JArray.Parse(input))
{
foreach(var smallString in JArray.Parse(longString))
{
var values=smallString.Split(":");
if(values[1]=="bbl")
{
return values[2];
}
}
}
return null;
You could convert that to LINQ, but that would be just as hard to read :
var value=JArray.Parse(input)
.SelectMany(longString=>JArray.Parse(longString))
.Select(smallString=>smallString.Split(":"))
.Where(values=>values[1]=="bbl")
.Select(values=>values[2])
.FirstOrDefault();
I have some ini file include this string : _DeviceName = #1234. Now I want to get the _DeviceName value that is 1234 but it shows me the full string that is _DeviceName = #1234.
I tried this code:
if (File.Exists("inifile.ini"))
{
if (File.ReadAllText("inifile.ini").Split('\r', '\n').First(st => st.StartsWith("_DeviceName")) != null)
{
string s = File.ReadAllText("inifile.ini").Split('\r', '\n').First(st => st.StartsWith("_DeviceName"));
MessageBox.Show(s);
}
}
You can use File.ReadAllLines instead. You may want to look at existing ini file readers if you're doing anything more complex but this should work. As a side note, it's not efficient to make two File.ReadAllText calls so quickly; in most cases it's best to just store the result in a variable).
if (File.Exists("inifile.ini"))
{
string[] allLines = File.ReadAllLines("inifile.ini");
string deviceLine = allLines.Where(st => st.StartsWith("_DeviceName")).FirstOrDefault();
if(!String.IsNullOrEmpty(deviceLine))
{
string value = deviceLine.Split('=')[1].Trim();
MessageBox.Show(value);
}
}
You could add another split to get the value out:
if (File.Exists("inifile.ini"))
{
if (File.ReadAllText("inifile.ini").Split('\r', '\n').First(st => st.StartsWith("_DeviceName")) != null)
{
string s = File.ReadAllText("inifile.ini")
.Split('\r', '\n').First(st => st.StartsWith("_DeviceName"))
.Split('=')[1];
MessageBox.Show(s);
}
}
I made an application that implements an INI Reader/Writer. Source code not available just yet, but keep checking back, I will have the source uploaded in a few days ( today is 8/14/13) . This particular INI Reader is CASE SENSITIVE and may need modification for special characters, but so far I have had no problems.
http://sourceforge.net/projects/dungeonchest/
A dirty way would be to use String.Replace("_DeviceName = #", "")
As of now, I am using this code to open a file and read it into a list and parse that list into a string[]:
string CP4DataBase =
"C:\\Program\\Line Balancer\\FUJI DB\\KTS\\KTS - CP4 - Part Data Base.txt";
CP4DataBaseRTB.LoadFile(CP4DataBase, RichTextBoxStreamType.PlainText);
string[] splitCP4DataBaseLines = CP4DataBaseRTB.Text.Split('\n');
List<string> tempCP4List = new List<string>();
string[] line1CP4Components;
foreach (var line in splitCP4DataBaseLines)
tempCP4List.Add(line + Environment.NewLine);
string concattedUnitPart = "";
foreach (var line in tempCP4List)
{
concattedUnitPart = concattedUnitPart + line;
line1CP4PartLines++;
}
line1CP4Components = new Regex("\"UNIT\",\"PARTS\"", RegexOptions.Multiline)
.Split(concattedUnitPart)
.Where(c => !string.IsNullOrEmpty(c)).ToArray();
I am wondering if there is a quicker way to do this. This is just one of the files I am opening, so this is repeated a minimum of 5 times to open and properly load the lists.
The minimum file size being imported right now is 257 KB. The largest file is 1,803 KB. These files will only get larger as time goes on as they are being used to simulate a database and the user will continually add to them.
So my question is, is there a quicker way to do all of the above code?
EDIT:
***CP4***
"UNIT","PARTS"
"BLOCK","HEADER-"
"NAME","106536"
"REVISION","0000"
"DATE","11/09/03"
"TIME","11:10:11"
"PMABAR",""
"COMMENT",""
"PTPNAME","R160805"
"CMPNAME","R160805"
"BLOCK","PRTIDDT-"
"PMAPP",1
"PMADC",0
"ComponentQty",180
"BLOCK","PRTFORM-"
"PTPSZBX",1.60
"PTPSZBY",0.80
"PTPMNH",0.25
"NeedGlue",0
"BLOCK","TOLEINF-"
"PTPTLBX",0.50
"PTPTLBY",0.40
"PTPTLCL",10
"PTPTLPX",0.30
"PTPTLPY",0.30
"PTPTLPQ",30
"BLOCK","ELDT+" "PGDELSN","PGDELX","PGDELY","PGDELPP","PGDELQ","PGDELP","PGDELW","PGDELL","PGDELWT","PGDELLT","PGDELCT","PGDELR"
0,0.000,0.000,0,0,0.000,0.000,0.000,0.000,0.000,0.000,0
"BLOCK","VISION-"
"PTPVIPL",0
"PTPVILCA",0
"PTPVILB",0
"PTPVICVT",10
"PENVILIT",0
"BLOCK","ENVDT"
"ELEMENT","CP43ENVDT-"
"PENNMI",1.0
"PENNMA",1.0
"PENNZN",""
"PENNZT",1.0
"PENBLM",12
"PENCRTS",0
"PENSPD1",100
"PTPCRDCT",0
"PENVICT",1
"PCCCRFT",1
"BLOCK","CARRING-"
"PTPCRAPO",0
"PTPCRPCK",0
"PTPCRPUX",0.00
"PTPCRPUY",0.00
"PTPCRRCV",0
"BLOCK","PACKCLS-"
"FDRTYPE","Emboss"
"TAPEWIDTH","8mm"
"FEEDPITCH",4
"REELDIAMETER",0
"TAPEDEPTH",0.0
"DOADVVACUUM",0
"CHKBEFOREFEED",0
"TAPEARMLENGTH",0
"PPCFDPP",0
"PPCFDEC",4
"PPCMNPT",30
"UNIT","PARTS"
"BLOCK","HEADER-"
"NAME","106653"
"REVISION","0000"
"DATE","11/09/03"
"TIME","11:10:42"
"PMABAR",""
"COMMENT",""
"PTPNAME","0603R"
"CMPNAME","0603R"
"BLOCK","PRTIDDT-"
"PMAPP",1
"PMADC",0
"ComponentQty",18
"BLOCK","PRTFORM-"
"PTPSZBX",1.60
"PTPSZBY",0.80
"PTPMNH",0.23
"NeedGlue",0
"BLOCK","TOLEINF-"
"PTPTLBX",0.50
"PTPTLBY",0.34
"PTPTLCL",0
"PTPTLPX",0.60
"PTPTLPY",0.40
"PTPTLPQ",30
"BLOCK","ELDT+" "PGDELSN","PGDELX","PGDELY","PGDELPP","PGDELQ","PGDELP","PGDELW","PGDELL","PGDELWT","PGDELLT","PGDELCT","PGDELR"
0,0.000,0.000,0,0,0.000,0.000,0.000,0.000,0.000,0.000,0
"BLOCK","VISION-"
"PTPVIPL",0
"PTPVILCA",0
"PTPVILB",0
"PTPVICVT",10
"PENVILIT",0
"BLOCK","ENVDT"
"ELEMENT","CP43ENVDT-"
"PENNMI",1.0
"PENNMA",1.0
"PENNZN",""
"PENNZT",1.0
"PENBLM",12
"PENCRTS",0
"PENSPD1",80
"PTPCRDCT",0
"PENVICT",1
"PCCCRFT",1
"BLOCK","CARRING-"
"PTPCRAPO",0
"PTPCRPCK",0
"PTPCRPUX",0.00
"PTPCRPUY",0.00
"PTPCRRCV",0
"BLOCK","PACKCLS-"
"FDRTYPE","Emboss"
"TAPEWIDTH","8mm"
"FEEDPITCH",4
"REELDIAMETER",0
"TAPEDEPTH",0.0
"DOADVVACUUM",0
"CHKBEFOREFEED",0
"TAPEARMLENGTH",0
"PPCFDPP",0
"PPCFDEC",4
"PPCMNPT",30
... the file goes on and on and on.. and will only get larger.
The REGEX is placing each "UNIT PARTS" and the following code until the NEXT "UNIT PARTS" into a string[].
After this, I am checking each string[] to see if the "NAME" section exists in a different list. If it does exist, I am outputting that "UNIT PARTS" at the end of a textfile.
This bit is a potential performance killer:
string concattedUnitPart = "";
foreach (var line in tempCP4List)
{
concattedUnitPart = concattedUnitPart + line;
line1CP4PartLines++;
}
(See this article for why.) Use a StringBuilder for repeated concatenation:
// No need to use tempCP4List at all
StringBuilder builder = new StringBuilder();
foreach (var line in splitCP4DataBaseLines)
{
concattedUnitPart.AppendLine(line);
line1CP4PartLines++;
}
Or even just:
string concattedUnitPart = string.Join(Environment.NewLine,
splitCP4DataBaseLines);
Now the regex part may well also be slow - I'm not sure. It's not obvious what you're trying to achieve, whether you need regular expressions at all, or whether you really need to do the whole thing in one go. Can you definitely not just process it line by line?
You could achieve the same output list 'line1CP4Components' using the following:
Regex StripEmptyLines = new Regex(#"^\s*$", RegexOptions.Multiline);
Regex UnitPartsMatch = new Regex(#"(?<=\n)""UNIT"",""PARTS"".*?(?=(?:\n""UNIT"",""PARTS"")|$)", RegexOptions.Singleline);
string CP4DataBase =
"C:\\Program\\Line Balancer\\FUJI DB\\KTS\\KTS - CP4 - Part Data Base.txt";
CP4DataBaseRTB.LoadFile(CP4DataBase, RichTextBoxStreamType.PlainText);
List<string> line1CP4Components = new List<string>(
UnitPartsMatch.Matches(StripEmptyLines.Replace(CP4DataBaseRTB.Text, ""))
.OfType<Match>()
.Select(m => m.Value)
);
return line1CP4Components.ToArray();
You may be able to ignore the use of StripEmptyLines, but your original code is doing this via the Where(c => !string.IsNullOrEmpty(c)). Also your original code is causing the '\r' part of the "\r\n" newline/linefeed pair to be duplicated. I assumed this was an accident and not intentional?
Also you don't seem to be using the value in 'line1CP4PartLines' so I omitted the creation of the value. It was seemingly inconsistent with the omission of empty lines later so I guess you're not depending on it. If you need this value a simple regex can tell you how many new lines are in the string:
int linecount = new Regex("^", RegexOptions.Multiline).Matches(CP4DataBaseRTB.Text).Count;
// example of what your code will look like
string CP4DataBase = "C:\\Program\\Line Balancer\\FUJI DB\\KTS\\KTS - CP4 - Part Data Base.txt";
List<string> Cp4DataList = new List<string>(File.ReadAllLines(CP4DataBase);
//or create a Dictionary<int,string[]> object
string strData = string.Empty;//hold the line item data which is read in line by line
string[] strStockListRecord = null;//string array that holds information from the TFE_Stock.txt file
Dictionary<int, string[]> dctStockListRecords = null; //dictionary object that will hold the KeyValuePair of text file contents in a DictList
List<string> lstStockListRecord = null;//Generic list that will store all the lines from the .prnfile being processed
if (File.Exists(strExtraLoadFileLoc + strFileName))
{
try
{
lstStockListRecord = new List<string>();
List<string> lstStrLinesStockRecord = new List<string>(File.ReadAllLines(strExtraLoadFileLoc + strFileName));
dctStockListRecords = new Dictionary<int, string[]>(lstStrLinesStockRecord.Count());
int intLineCount = 0;
foreach (string strLineSplit in lstStrLinesStockRecord)
{
lstStockListRecord.Add(strLineSplit);
dctStockListRecords.Add(intLineCount, lstStockListRecord.ToArray());
lstStockListRecord.Clear();
intLineCount++;
}//foreach (string strlineSplit in lstStrLinesStockRecord)
lstStrLinesStockRecord.Clear();
lstStrLinesStockRecord = null;
lstStockListRecord.Clear();
lstStockListRecord = null;
//Alter the code to fit what you are doing..
I'm still trying to understand KeyValuePairs but I believe this idea should work. In my code below it searchs through a large string and extracts 2 substrings. One substring (keep in mind the value between the quotes varies) is something like Identity="EDN\username" another substring is something like FrameworkSiteID="Desoto" So I was thinking about combining these strings together before I added them to the List but here is my problem.. The login string below is a Unique field of strings that I need to use in a SQL statement to select records in SQLServer and the framew strings are strings I need lined up with the login strings (and all the columns and rows of data coming from SQLServer) when I output this to a text file. Should I make the login strings KEYS and the framew strings VALUES? If so how do I do that?? Hope that makes sense. I can further explain if needs be
Regex reg = new Regex("Identity=\"[^\"]*\"");
Regex reg1 = new Regex("FrameworkSiteID=\"[^\"]*\"");
foreach (FileInfo file in Files)
{
string line = "";
using (StreamReader sr = new StreamReader(file.FullName))
{
while (!String.IsNullOrEmpty(line = sr.ReadLine()))
{
if (line.ToUpper().Contains("IDENTITY="))
{
string login = reg.Match(line).Groups[0].Value;
string framew = reg1.Match(line).Groups[0].Value; //added
IdentityLines.Add(new KeyValuePair<string, string>(file.Name, login + " " + framew));
//This is probably not what I need
}
else
{
IdentityLines.Add(new KeyValuePair<string, string>(file.Name, "NO LOGIN"));
}
}
KeyValuePair<TKey,TValue> is a structure used by the Dictionary<TKey,TValue> class. Instead of keeping a list of KeyValuePair<TKey,TValue> objects, just create a Dictionary<TKey,TValue> and add keys/values to it.
Example:
Dictionary<string,string> identityLines = new Dictionary<string,string>();
foreach (FileInfo file in Files)
{
string line = "";
using (StreamReader sr = new StreamReader(file.FullName))
{
while (!String.IsNullOrEmpty(line = sr.ReadLine()))
{
if (line.ToUpper().Contains("IDENTITY="))
{
string login = reg.Match(line).Groups[0].Value;
string framew = reg1.Match(line).Groups[0].Value; //added
identityLines.Add(login, framew);
}
}
}
}
This will create an association between logins and framews. If you want to sort these by file, you can make a Dictionary<string, Dictionary<string,string>> and associate each identityLines dictionary with a specific filename. Note that the key values of the Dictionary<TKey, TValue> type are unique - you will get an error if you try to add a key that has already been added.
I'm note clear what the purpose of this is. You don't seem to be using the KeyValuePairs as pairs of a Key and a Value. Are you using them as a general pair class? It's a reasonable use (I do this myself), but I'm not sure what help you are seeking.
The intended purpose of KeyValuePair is as a helper-class in the implementation of Dictionaries. This would be useful if you are going to look up values based on having a key, though it doesn't seem from your explanation that you are.
Why are you using the filename as the key? Does it matter?
I also don't see why you are loading all of this stuff into a list. Why not just yield them out and use them as they are found?
foreach (FileInfo file in Files)
{
using (StreamReader sr = new StreamReader(file.FullName))
{
for(string line = sr.ReadLine(); !string.IsNullOrEmpty(line); line = sr.ReadLine())
{
if(line.IndexOf("IDENTITY=", StringComparison.InvariantCultureIgnoreCase) != -1)
{
string login = reg.Match(line).Groups[0].Value;
string framew = reg1.Match(line).Groups[0].Value; //added
yield return new KeyValuePair<string, string>(login, framew));
}
}
}
}
On the other hand, if you do want to use them as key-d values:
Dictionary<string, string> logins = new Dictionary<string, string>();
foreach (FileInfo file in Files)
{
using (StreamReader sr = new StreamReader(file.FullName))
{
for(string line = sr.ReadLine(); !string.IsNullOrEmpty(line); line = sr.ReadLine())
{
if(line.IndexOf("IDENTITY=", StringComparison.InvariantCultureIgnoreCase) != -1)
{
string login = reg.Match(line).Groups[0].Value;
string framew = reg1.Match(line).Groups[0].Value; //added
logins.Add(login, framew));
}
}
}
}
Now logins[login] returns the related framew. If you want this to be case-insensitive then use new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase) or new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase) as appropriate.
Finally, are you sure there will be no blank likes until the end of the file? If there could be you should use line != null rather than !string.IsNullOrEmpty() to avoid stopping your file read prematurely.