I currently have:
string settings = "setting1:value1;setting2:value2";
string[] pair;
foreach(string setting in settings.Split(';'))
{
pair = setting.Split(':');
MessageBox.Show(pair[0] + ":" + pair[1]);
}
I would something more along the lines of:
string settings = "setting1:value1;setting2:value2";
foreach (string[] pair in string setting.Split(':') in settings.Split(';'))
{
MessageBox.Show(pair[0] + ":" + pair[1]);
}
The two in keywords seem a bit ridiculous, but I would think something like this would be possible and very easy, I just don't know how.
So, is it possible?
I'm not sure this is more readable, but you asked for it and I think it looks cool ;-)
string settings = "setting1:value1;setting2:value2";
foreach(var pair in settings.Split(';').Select(str => str.Split(':')))
{
MessageBox.Show(pair[0] + ":" + pair[1]);
}
(I haven't compiled it, so I'm sorry if there are syntax errors)
As an alternative to the other posted answers, you can also use the LINQ syntax:
string settings = "setting1:value1;setting2:value2";
foreach(string[] pair in
from setting in settings.Split(';')
select setting.Split(':'))
{
MessageBox.Show(pair[0] + ":" + pair[1]);
}
foreach (string[] pair in settings.Split(';').Select(setting => setting.Split(':')))
{
MessageBox.Show(pair[0] + ":" + pair[1]);
}
foreach (string settingstr in settings.Split(';'))
{
string[] setval = settingstr.Split(':');
string setting = setval[0];
string val = setval[1];
}
Related
I am using Mailkit to send an email.
So in the body of the email, I am passing data like this:
message.Body = new TextPart("plain")
{
foreach (var item in model.Transaction)
{
Console.WriteLine(item.Account +"-"+item.Amount+"-"+item.Date);
}
Text = #"";
};
but I wanted to put item.Account, item.Amount, item.Date in #""
How can I do that?
you should use $
$"{item.Account}, {item.Amount}, {item.Date}";
Because # is used to escaping specials symbols
You won't be able to access item.* outside of foreach*.
To create a single string from multiple strings you could use string.Join:
List<string> l = new ();
foreach (var item in model.Transaction)
{
var fromSingleItem = $"{item.Account}-{item.Amount}-{item.Date}";
l.Append(fromSingleItem);
}
var fromAllItems = string.Join(", ", l);
* = What would time outside of foreach mean? Would it be the first item's data, or the last one's, or from the middle?
I would use a string builder for this
var sb= new StringBuilder();
foreach (var item in model.Transaction)
{
sb.Append( item.Account + "-" + item.Amount.ToString() + "-"
+ item.Date.ToString() + "\n");
}
message.Body = new TextPart("plain")
{
Text = sb.ToString();
};
or if you have only several items
var sb= string.Empty;
foreach (var item in model.Transaction)
{
sb+= item.Account + "-" + item.Amount.ToString() + "-" + item.Date.ToString() + "\n");
}
Serge has the right idea, but I would tweak it a bit as there is a performance penalty every time you concatenate using the '+' symbol (a new String object is instantiated when you concatenate with '+'). I would suggest you continue to use StringBuilder even if you only have a single item in your foreach loop.
var builder = new StringBuilder();
foreach (var item in model.Transaction)
{
builder.Append(item.Account);
builder.Append("-");
builder.Append(item.Amount);
builder.Append("-");
builder.AppendLine(item.Date);
}
message.Body = new TextPart("plain")
{
Text = builder.ToString()
};
I am writing a application which sorts out data from a csv to txt.
I have witten but I cannot get the required output.
Can someone please help, I do not see were I went wrong.
I initially thought its the File.WriteAllLines which was the problem but even when I write to a console I get the same results.
My file looks something like this
Georgina,Sinclair,408999703657,cheque,First National Bank,Fourways,275.00,12/01/2012
Zachary,Whitehead,409122372301,cheque,ABSA,Irene,70.25,12/01/2012
Toby,Henderson,401255489873,cheque,First National Bank,Edenvale,181.03,12/13/2012
Katherine,Cooke,409155874935,savings,ABSA,Southdowns,975.89,01/01/2013
Bradley,James,409254998,savings,ABSA,Melville,207.74,12/09/2012
Sophie,Lane,409771987,savings,ABSA,Roodepoort,207.74,12/31/2012
My output should be something like this
First National B0020000045603
GSinclair 408999703657 CH Fourways 002750001122012
THenderson 401255489873 CH Edenvale 001810313122012
ABSA 0040000146162
ZWhitehead 409122372301 CH Irene 000702501122012
KCooke 409155874935 SAVSouthdowns009758901012013
BJames 409254998 SAVMelville 002077409122012
SLane 409771987 SAVRoodepoort002077431122012
The code I currently have only returns the header and 2 lines which looks as follows.
ABSA 0040000146162
KCooke 409155874935 SAVSouthdowns 009758901012013
Please assist.
My code looks as follows
string text = #"C:\\Test\\output.txt";
var inputEntries = File.ReadLines(#"C:\\Test\\debitorders.csv").Select(line =>
{
var values = line.Split(',');
return new
{
accountholder = values[0].Trim().Substring(0, 1) + values[1].Trim(),
accountnumber = long.Parse(values[2].Trim()),
accounttype = values[3].Trim(),
bankname = values[4].Trim(),
branch = values[5].Trim(),
amount = 100 * double.Parse(values[6].Trim()),
date = DateTime.Parse(values[7].Trim())
};
});
var banks = inputEntries
.OrderBy(e => e.bankname)
.GroupBy(e => e.bankname, e => e);
foreach (var bank in banks)
{
var AccountName = bank.Key;
if (AccountName.Length >= 20)
{
AccountName = AccountName.Substring(0, 16);
}
else
{
AccountName += new string(' ', 20 - AccountName.Length);
}
var NumberOfAccounts = bank.Count();
var TotalAmount = bank.Select(acc => acc.amount).Sum();
var Header = AccountName + "\t" + NumberOfAccounts.ToString("000") + TotalAmount.ToString("0000000000");
var sortedAccounts = bank
.OrderBy(acc => acc.accountholder)
.OrderByDescending(acc => acc.amount);
foreach (var account in sortedAccounts)
{
var outputLine =
account.accountholder + "\t" +
account.accountnumber + "\t" +
//get first 2 characters
account.accounttype.Substring(0, 3).ToUpper() + account.branch + "\t" + "00" +
account.amount +
account.date.ToString("ddMMyyyy");
for (int i = 0; i < 15; i++)
{
File.WriteAllText(text, Header + Environment.NewLine + outputLine);
Console.WriteLine(Header + outputLine);
Console.ReadLine();
}
}
}
A better and cleaner solution will be to make use of List<string> to which you add your text. At the end of the code just convert the list to an array and write all lines to a file.
List<string> outputLine = new List<string>(); //note this addition to the code
foreach (var bank in banks)
{
//do header formatting stuff here
var Header = somecode
outputLine.Add(Header); //Add Header to outputLine
var sortedAccounts = bank.OrderBy(acc => acc.accountholder)
.OrderByDescending(acc => acc.amount);
foreach (var account in sortedAccounts)
{
var tempStringBuilder =
account.accountholder + "\t" +
account.accountnumber + "\t" +
//get first 2 characters
account.accounttype.Substring(0, 3).ToUpper() + account.branch + "\t" + "00" +
account.amount +
account.date.ToString("ddMMyyyy");
outputLine.Add(tempStringBuilder); //Add tempStringBuilder to outputLine
}
}
File.WriteAllLines("destination path", outputLine.ToArray()); //Write everything to your output file in one go
Alternative Excel solution:
Microsoft Excel has a really powerful tool called Pivot Tables, which is ideally suited to your needs. If you are unfamiliar with it, read some tutorials about it. At first it's a process to get your head around the workflow to use it but it is quite simple once you've grasped it. You just drag and drop fields by which you want to group.
You might also want to consider using Data Connections to link to your original data, which is also quite simple given the dataset you have.
I think i found the solution:
File.AppendAllText(text, Header + Environment.NewLine + outputLine + Environment.NewLine);
Use File.AppendAllText instead of File.WriteAllText. With WriteAllText you always deleted the old content.
But consider to clean the file (File.WriteAllText(text, "");) before you begin to write on it, otherwise you will have the old data from last run also in it.
Try to use String.Format("{0,-10}", name) which means that the length of the name is filled up with spaces up to the length of 10. Minus means left alignment and positive causes right alignment.
I updated your code to:
string text = #"D:\C#\output.txt";
File.WriteAllText(text, "");
var inputEntries = File.ReadLines(#"D:\c#\debitorders.csv").Select(line =>
{
var values = line.Split(',');
return new
{
accountholder = values[0].Trim().Substring(0, 1) + values[1].Trim(),
accountnumber = long.Parse(values[2].Trim()),
accounttype = values[3].Trim(),
bankname = values[4].Trim(),
branch = values[5].Trim(),
amount = 100 * double.Parse(values[6].Trim()),
date = DateTime.ParseExact(values[7].Trim(), "MM/dd/yyyy", CultureInfo.InvariantCulture)
};
});
var banks = inputEntries.OrderBy(e => e.bankname)
.GroupBy(e => e.bankname, e => e);
foreach (var bank in banks)
{
var AccountName = bank.Key;
var NumberOfAccounts = bank.Count();
var TotalAmount = bank.Select(acc => acc.amount).Sum();
var Header = String.Format("{0,-20} {1,-10} {2}", AccountName, NumberOfAccounts.ToString("000"), TotalAmount.ToString("0000000000"));
var sortedAccounts = bank.OrderBy(acc => acc.accountholder)
.OrderByDescending(acc => acc.amount);
File.AppendAllText(text, Header + Environment.NewLine);
Console.WriteLine(Header);
foreach (var account in sortedAccounts)
{
var outputLine = String.Format("{0,-11} {1,15} {2,-3} {3,-10} {4,7} {5,-10}",
account.accountholder,
account.accountnumber,
account.accounttype.Substring(0, 3).ToUpper(),
account.branch,
account.amount,
account.date.ToString("ddMMyyyy")
);
//get first 2 characters
//account.accounttype.Substring(0, 3).ToUpper() + account.branch + "\t" + "00" +
// what are the "00" for? didn't include them you may this do by yourself
File.AppendAllText(text, outputLine + Environment.NewLine);
Console.WriteLine(outputLine);
}
File.AppendAllText(text, Environment.NewLine);
Console.WriteLine();
}
Output is:
ABSA 004 0000146162
KCooke 409155874935 SAV Southdowns 97589 01012013
BJames 409254998 SAV Melville 20774 09122012
SLane 409771987 SAV Roodepoort 20774 31122012
ZWhitehead 409122372301 CHE Irene 7025 01122012
First National Bank 002 0000045603
GSinclair 408999703657 CHE Fourways 27500 01122012
THenderson 401255489873 CHE Edenvale 18103 13122012
i'm reading a file with 10002 lines, in each line there is a name that I want to compare with a single string, and if this string is the same, i want to add the string file to a listbox, I'm using the FILE.READLINE and then add each line to a list then I use .CONTAINS method and doesnt works also with == but that doesn work either...Any suggestions?
//This is my code:
foreach (string h in Directory.EnumerateFiles(NomDirec, "resume*"))
{
this.listBox1.Items.Add(h);
//Read Lines here and add them to a list and a listbox
var NombreLinea = File.ReadLines(h);
foreach (var item in NombreLinea)
{
NombreAbuscar.Add(item).Remove(item.IndexOf(":"));
this.listBox3.Items.Add(item);
}
//Here I want to add this file only if "NombreCompleto" is present in my resume file.
foreach (string t in Directory.EnumerateFiles(NomDirec, "ESSD1*"))
{
string[] Nombre = File.ReadLines(t).ElementAtOrDefault(6).Split(':');
string[] ApellidoPat = File.ReadLines(t).ElementAtOrDefault(7).Split(':');
string[] ApellidoMat = File.ReadLines(t).ElementAtOrDefault(8).Split(':');
string NombreCompleto = ApellidoPat[1] + ApellidoMat[1] + "," + " " + Nombre[1] + " " + ":";
foreach (var item in NombreAbuscar)
{
if (NombreCompleto == item)
{
this.listBox1.Items.Add(t);
break;
}
}
}
Could be a way to only read the a certain part of the line and add it to my listbox??
The following piece of code achives the desired results, but performance is extremely slow:
SearchResultCollection absaUsers = ABSAds.FindAll();
SearchResultCollection srcUsers = ds.FindAll();
foreach (SearchResult users in srcUsers)
{
string cn = users.Properties["cn"][0].ToString();
string sn = users.Properties["sn"][0].ToString();
string userID = users.Properties["uid"][0].ToString();
string description = users.Properties["PersonnelAreaDesc"][0].ToString();
string jobCodeID = users.Properties["JobcodeID"][0].ToString();
string CostCentreID = users.Properties["costCentreID"][0].ToString();
string CostCentreDescription = users.Properties["CostCentreDescription"][0].ToString();
string givenName = users.Properties["givenName"][0].ToString();
string employmentStatus = users.Properties["EmploymentStatus"][0].ToString();
string EmploymentStatusDescription = users.Properties["EmploymentStatusDescription"][0].ToString();
foreach (SearchResult absaUser in absaUsers)
{
string absaUID = absaUser.Properties["uid"][0].ToString();
string absaEmploymentStatus = absaUser.Properties["EmploymentStatus"][0].ToString();
string absaEmploymentStatusDescription = absaUser.Properties["EmploymentStatusDescription"][0].ToString();
string absaEmployeeNumber = absaUser.Properties["employeeNumber"][0].ToString();
if (absaUID == cn && absaEmployeeNumber==userID)
{
Console.WriteLine("User Record Found:" + cn);
sw.WriteLine("Modify" + "," + cn + "," + description + "," + userID + "," + givenName + "," + sn + "," + jobCodeID + "," + CostCentreID + "," + CostCentreDescription + "," + sn + "," + cn + "," + employmentStatus + "," + EmploymentStatusDescription);
sw.Flush();
break;
}
}
}
It loops through 2 collections and mtaches the outer loops attributes with the inner's. Any suggestions on how I can optimise the performance?
It would be faster if you extracted all the absaUID values to a lookup first:
var lookup = absaUsers.Cast<SearchResult>()
.ToLookup(x => x.Properties["uid"][0].ToString());
Then you can just use:
foreach (SearchResult users in srcUsers)
{
string cn = users.Properties["cn"][0].ToString();
foreach (SearchResult matches in lookup[cn])
{
...
}
}
You haven't shown how absaUsers is defined - if it's a LINQ query expression, then it could be that your existing code will be going to the database on every iteration at the moment - whereas the above won't. On the other hand, if srcUsers is also a LINQ query expression talking to a database, you should consider doing all the matching at the database using a join instead.
you could use LINQ join, some examples are here, I'm assuming whoever built it into .NET found a pretty optimal way of doing that, and then loop through that. on a sidenote: what are your collection types? please add their declaration to the code snippet.
Use Lamda expressions:
Below is the sample one , You can optizime this to another level.
List<SearchResult> allResultGroups=new List<SearchResult>();
foreach (SearchResult absaUser in absaUsers)
{
resultGroups = srcUsers.Where(g => g.cn == absaUser.absaUID && absaUser.absaEmployeeNumber==g.userID ).ToList();
}
Alright so I've looked hard but I couldn't seem to find answer to my problem. There must be a problem in my code and it would be really helpful if someone could look at it for me.
Dictionary<string, string> keylist = new Dictionary<string, string>();
if (intext.Contains("addkey") && intext.Contains("def"))
{
string[] keywords = intext.Split(' ');
string key1 = keywords[1];
string def2 = keywords[3];
string fkey = key1.Replace("_", " ");
string fdef = def2.Replace("_", " ");
keylist.Add(fkey, fdef);
say("Phrase '" + fkey + "' added with response '" + fdef + "'");
say("Your Dictionary contains " + keylist.Count.ToString() + " word(s).");
//////////////////////////////
}
All I want it to do is take the input in the form of "addkey key_here def definition_here" and add it to the dictionary. I added the counting part for debugging purposes and it always says I only have 1 word in the dictionary no matter how many I have added. You can probably tell I'm new so please be gentle. Thanks
Dictionary<string, string> keylist = new Dictionary<string, string>();
I'm assuming that this function is called whenever the user enters some sort of command (e.g. from the command line, when they click a button, etc.). If this is the case, you need to have your keylist dictionary at a higher level (as an instance variable, for example). The way the code is now, every time the function is called a new dictionary is created and the key is added to it; this is why there's only one.
At the risk of misjudging or oversimplifying your problem, just moving the line I quoted above outside of the function body should help.
In the code as given you are recreating the dictionary every time you run it.
Dictionary<string, string> keylist = new Dictionary<string, string>();
Reinitializes the variable keylist to an empty dictionary.
Instead try moving that line outside of the function. Since you are using winforms, you can create a class level variable, something like this:
public partial class Form1 : Form
{
Dictionary<string, string> keylist = new Dictionary<string, string>();
public Form1()
{
InitializeComponent();
}
public void YourFunction(string intext)
{
if (intext.Contains("addkey") && intext.Contains("def"))
{
string[] keywords = intext.Split(' ');
string key1 = keywords[1];
string def2 = keywords[3];
string fkey = key1.Replace("_", " ");
string fdef = def2.Replace("_", " ");
keylist.Add(fkey, fdef);
say("Phrase '" + fkey + "' added with response '" + fdef + "'");
say("Your Dictionary contains " + keylist.Count.ToString() + " word(s).");
}
}
}
You need to loop through the if (intext.Contains...{} block or it only runs once. If you are looping through it and only getting one entry in the Dictionary, it's because you keep reassigning it within the scope in a scenario such as:
while(true) {
Dictionary<string, string> keylist = new Dictionary<string,string>();
//...
}
So you'll need to move it outside, if that's your case.
I'm not sure exactly what your input string is or how you need to use it, though I think you're looking to split the input string and loop through along this line...
private Dictionary<string, string> GetData(string intext)
{
Dictionary<string, string> keylist = new Dictionary<string, string>();
string[] keywords = intext.Split(' ');
foreach (string s in keywords)
{
if (s.Contains("addkey") && s.Contains("def"))
{
string fkey = key1.Replace("_", " ");
string fdef = def2.Replace("_", " ");
keylist.Add(fkey, fdef);
say("Phrase '" + fkey + "' added with response '" + fdef + "'");
say("Your Dictionary contains " + keylist.Count.ToString() + " word(s).");
}
}
return keylist;
}