Filtering strings out of an array - c#

I'm trying to design a check on incoming strings for an array, and if the incoming string has a specific starting character it gets skipped over
For example:
;item1
item2
item3
;item4
should be put into array as
item2
item3
I thought I'd try to use a foreach method to skip the line that starts with the identifier, and then in the else append the lines that don't match back into the string array, but it doesn't seem I am able to do this.
Help!
void Whitelist()
{
if (logging == 1)
{
FIO._Log("Performing WhiteList func", writer);
}
try
{
string[] lines = File.ReadAllLines("Whitelist.ini");
string[] lines2;
foreach (string line in lines)
{
if (line.StartsWith(";"))
{
continue;
}
else
{
// lines2.append(line) ??
}
}
structs.CustomWhiteList = lines2;
}
catch (Exception e)
{
MessageBox.Show("Error reading whitelist file." + Environment.NewLine + e.Message);
FIO._Log("Failed to read whitelist file", writer);
}
}

You can read the lines in, filter out the ones starting with a semicolon, and then set the resulting array directly to CustomWhiteList.
Try the following code:
var lines = File.ReadAllLines("Whitelist.ini");
structs.CustomWhiteList = lines.Where(x => !x.StartsWith(";")).ToArray();
This uses LINQ, so you'll have to add using System.Linq to your class if it's not already there.

Related

Problems with List<string> when adding strings by variable

I wanna do a list without duplicates from a file which have too many lines with identifier, sometimes repeated. When I try using List<string>.Contains, it doesn't work. This is, I think, because I'm adding object instead of strings directly.
public List<string> obterRelacaoDeBlocos()
{
List<string> listaDeBlocos = new List<string>();
foreach(string linhas in arquivos.obterLinhasDoArquivo())
{
string[] linhaQuebrada = linhas.Split('|');
string bloco = linhaQuebrada[1].ToString();
if (listaDeBlocos.Contains((string)bloco) != true)
{
listaDeBlocos.Add( bloco + ":" + listaDeBlocos.Contains(bloco).ToString());
}
}
return listaDeBlocos;
}
You're appending ":" + listaDeBlocos.Contains(bloco).ToString() to the string before you add it to the list. That's not going to match when you encounter the same word again, so Contains will return false and the same word will get added again.
I don't see what point it serves to append ": true" to the end of each string in the list anyway, so just remove that part and it should work.
if (!listaDeBlocos.Contains(bloco))
{
listaDeBlocos.Add(bloco);
}
Since you're only interested in one part of each string, based on how you're splitting, you could rewrite your method using LINQ. This is untested but should work:
public List<string> obterRelacaoDeBlocos()
{
return arquivos.obterLinhasDoArquivo().Select(x => x.Split('|')[1]).Distinct().ToList();
}

C# check conversion from List<string> to single string using String.Join, is possible or not?

I have one List<string> which length is undefined, and for some purpose I'm converting entire List<string> to string, so I want's to check before conversion that it is possible or not(is it gonna throw out of memory exception?) so I can process that much data and continue in another batch.
Sample
int drc = ImportConfiguration.Data.Count;
List<string> queries = new List<string>() { };
//iterate over data row to generate query and execute it
for (int drn = 0; drn < drc; drn++)//drn stands to Data Row Number
{
queries.Add(Generate(ImportConfiguration.Data[drn], drn));
//SO HERE I WANT"S TO CHECK FOR SIZE
//IF IT"S NOT POSSIBLE IN NEXT ITERATION THAN I'LL EXECUTE IT RIGHT NOW
//AND EMPTIED LIST AGAIN FOR NEXT BATCH
if (drn == drc - 1 || drn % 5000 == 0)
{
SqlHelper.ExecuteNonQuery(connection, System.Data.CommandType.Text, String.Join(Environment.NewLine, queries));
queries = new List<string>() { };
}
}
Since you are trying to send a large amount of text to a SQL Server instance, you could use SQL Server's streaming support to write the string to the stream as you go, minimizing the amount of memory needed to construct the data to send.
I can't say it is not possible but I think a better way would be to do the join and catch any exceptions:
try
{
var joined = string.Join(",", list);
}
catch(OutOfMemoryException)
{
// join failed, take action (log, notify user, etc.)
}
Note: if the exception is happening, then you need to consider a different approach than using a list and joining.
You could try:
List<string> theList;
try {
String allString = String.Join(",", theList.ToArray());
} catch (OutOfMemoryException e) {
// ... handle OutOfMemoryException exception (e)
}
EDIT
Based on your comment.
You could give an estimation in the following way.
Get available memory: Take a look at this post
Get sum size of your list strings theList.Sum(s => s.Length);
List<string> theList = new List<string>{ "AAA", "BBB" };
// number of characters
var allSize = theList.Sum(s => s.Length);
// available memory
Process proc = Process.GetCurrentProcess();
var availableMemory = proc.PrivateMemorySize64;;
if (availableMemory > allSize) {
// you can try
try {
String allString = String.Join(",", theList.ToArray());
} catch (OutOfMemoryException e) {
// ... handle OutOfMemoryException exception (e)
}
} else {
// it is not going to work...
}

Generating IDs using StreamReader (Last Line)

I'm trying to generate Item IDs using StreamReader on my .CSV file (It has to be a .csv file). The Item ID should start at 1000 and go up (1001, 1002, etc.)
Right now, if the user presses "Generate ID", it will search the entire file for the value "1000", if it doesn't exist, it will write "1000" in the textbox.
Here's what I need help with: If the file contains "1000", I want it to read the LAST line, increase it by 1, then write the value in the textbox.. So, if my last value is 1005 in the .csv file, I want it to write 1006 in the textbox.
private void GenerateID_Click(object sender, EventArgs e)
{
try
{
string searchString = "1000";
using (StreamReader sr = new StreamReader("file.csv"))
{
string line;
while ((line = sr.ReadLine()) != null)
{
if (line.Contains(searchString))
{
/* If file contains 1000, read the LAST line
* (Whatever number that may be: 1001, 1002, 1003, etc.)
* and increase that number by 1, then write to textbox. */
}
else
{
invItemIDField.Text = Convert.ToString("1000");
}
}
}
}
catch (Exception)
{
MessageBox.Show("The file could not be read");
}
}
I suggest you use FileHelpers. It's the most suitable library for reading CSV files.
To install this, you need to install first NuGet. Once installed, go to Tools > Library Package Manager > Package Manager Console:
Then, type in: Install-Package Filehelpers
You're good to go!
Import FileHelpers to your code
using FileHelpers;
Create a class that describes the structure of your CSV:
DelimitedRecord("'")]
public class MyCsv
{
public int Column1; // Your ID column
public string SomeOtherColumn;
}
Create a List<MyCsv>:
List<MyCsv> myList;
Then, to load your CSV:
FileHelperEngine<MyCsv> engine = new FileHelperEngine<MyCsv>();
myList = new List<MyCsv>(engine.ReadFile("my.csv")); // replace with your filename or variable containing the filename
You can now read your CSV by accessing the list myList:
foreach(MyCsv line in myList) {
// Do something;
}
Each object inside that list corresponds to each row in your CSV. In order to access the first column of a row (given the foreach loop above):
line.Column1
So, if you need to compare values, you can either use LINQ or do the traditional loop-search:
foreach(MyCsv line in myList) {
if (txtId.Text == line.Column1.ToString()) {
found = true;
break;
}
}
Then, to get the id of the last row:
myList.[myList.Count - 1].Column1
You can do the rest. Cheers!
Here's my go at it, it's slighlty different from yours, but it works. Granted there are things you must consider, such as are the elements surrounded in quotes, are the line breaks \r\n, and the like:
int TextBoxValue = 1000;
var reader = new StreamReader(File.OpenRead(#"C:\Users\J\Desktop\New Text Document (4).txt"));
var contents = reader.ReadToEnd().Split(new string[] {"\r\n"}, StringSplitOptions.None);
var iValueExists = (from String sLine in contents
where sLine.Contains("1000")
select sLine).Count();
if (iValueExists > 0)
{
TextBoxValue = int.Parse(contents.Last().Split(new string[] {","}, StringSplitOptions.None).First()) + 1;
}
invItemIDField.Text = TextBoxValue;
reader.Close();

In C#, best way to check if stringbuilder contains a substring

I have an existing StringBuilder object, the code appends some values and a delimiter to it.
I want to modify the code to add the logic that before appending the text, it will check if it already exists in the StringBuilder. If it does not, only then will it append the text, otherwise it is ignored.
What is the best way to do so? Do I need to change the object to string type? I need the best approach that will not hamper performance.
public static string BuildUniqueIDList(context RequestContext)
{
string rtnvalue = string.Empty;
try
{
StringBuilder strUIDList = new StringBuilder(100);
for (int iCntr = 0; iCntr < RequestContext.accounts.Length; iCntr++)
{
if (iCntr > 0)
{
strUIDList.Append(",");
}
// need to do somthing like:
// strUIDList.Contains(RequestContext.accounts[iCntr].uniqueid) then continue
// otherwise append
strUIDList.Append(RequestContext.accounts[iCntr].uniqueid);
}
rtnvalue = strUIDList.ToString();
}
catch (Exception e)
{
throw;
}
return rtnvalue;
}
I am not sure if having something like this will be efficient:
if (!strUIDList.ToString().Contains(RequestContext.accounts[iCntr].uniqueid.ToString()))
Personally I would use:
return string.Join(",", RequestContext.accounts
.Select(x => x.uniqueid)
.Distinct());
No need to loop explicitly, manually use a StringBuilder etc... just express it all declaratively :)
(You'd need to call ToArray() at the end if you're not using .NET 4, which would obviously reduce the efficiency somewhat... but I doubt it'll become a bottleneck for your app.)
EDIT: Okay, for a non-LINQ solution... if the size is reasonably small I'd just for for:
// First create a list of unique elements
List<string> ids = new List<string>();
foreach (var account in RequestContext.accounts)
{
string id = account.uniqueid;
if (ids.Contains(id))
{
ids.Add(id);
}
}
// Then convert it into a string.
// You could use string.Join(",", ids.ToArray()) here instead.
StringBuilder builder = new StringBuilder();
foreach (string id in ids)
{
builder.Append(id);
builder.Append(",");
}
if (builder.Length > 0)
{
builder.Length--; // Chop off the trailing comma
}
return builder.ToString();
If you could have a large collection of strings, you might use Dictionary<string, string> as a sort of fake HashSet<string>.

C# streamreader if questions

I'm trying to write out the specific line of code that contains the IF statement. What appears to be happening if it never finds the code i'm looking to call in my if statement and i know it exists, it's a copy and paste. Also, how do i only write out the specific line that meets the if statement. Is there one where i should do a foreach? foreach (redsplitline in redsplitlines)
heres the code:
{
string linesplitnew = "ENDOB";
string[] redsplitlines = rdrred.ReadToEnd().Split(new string[] { linesplitnew }, StringSplitOptions.None);
string redpullline = "*BEGINOB\r\n6*";
string redpullline2 = "*BEGINOB\r\n13*";
if(redsplitlines.Contains(redpullline))
{
Console.WriteLine(redsplitlines);
}
else if(redsplitlines.Contains(redpullline2))
{
Console.WriteLine(redsplitlines);
}
}
Try this:
var lines = from line in redsplitlines
where line.Contains(redpullline) || line.Contains(redpullline2)
select line;
foreach (var l in lines)
Console.WriteLine(l);

Categories