Showing the result once - c#

I have the following code that shows my result in Messagebox but it shows each time only one ifi want to see the next one,I must click OK on message box to see the next. I want to see all result at the same time. May you comments your idea?
foreach (var resultwithindexss in resultss.Select((rr, iindex) => new { result2 = rr, Index = iindex }).OrderByDescending(rr => rr.result2).Take(number))
{
MessageBox.Show(string.Format("{0}: {1}", resultwithindexss.Index, resultwithindexss.result2));
}
PS: I tried the following code, But show no result.
System.Console.WriteLine(string.Format("{0}: {1}", resultwithindexss.Index, resultwithindexss.result2));
Thanks in advance

Use a StringBuilder to build "big" message and then display it
var sb = new StringBuilder();
foreach (var resultwithindexss in resultss
.Select((rr, iindex) => new { result2 = rr, Index = iindex })
.OrderByDescending(rr => rr.result2)
.Take(number))
{
sb.AppendFormat("{0}: {1}", resultwithindexss.Index, resultwithindexss.result2));
sb.AppendLine();
}
MessageBox.Show(sb.ToString());

It's because you're extracting every result and display it instantly instead of adding it to a string and after the loop to display it.
This should do the trick(have not tested it):
var sb = new StringBuilder("");
foreach (var resultwithindexss in resultss.Select((rr, iindex) => new { result2 = rr, Index = iindex }).OrderByDescending(rr => rr.result2).Take(number))
{
sb.AppendFormat(string.Format("{0}: {1}\r\n", resultwithindexss.Index, resultwithindexss.result2));
}
MessageBox.Show(sb.ToString());

Related

c# dynamically modifying list

I don't understand how to do it with foreach...
The goal is to modify a list each time we change Num.
Is the way with a Canvas List and a working List is ok for nice coding?
class Program
{
static void Main(string[] args)
{
int i_Num = 0;
string Str_Num = "";
string[] linkToPLC = {"toto[{0}].test{1}", "tata[{0}].test{1}", "titi[{0}].test{1}"};
List<string> genlnkPLCCanvas = new List<string>(linkToPLC);
List<string> genlnkPLCworkingwith = new List<string>(linkToPLC);
Console.WriteLine("Insert Num: ");
Str_Num = Console.ReadLine();
i_Num = Convert.ToInt32(Str_Num);
for (int item = 0; item < genlnkPLCCanvas.Count; item++)
{
genlnkPLCworkingwith[item] = String.Format(genlnkPLCworkingwith[item], i_Num, 200);
Console.WriteLine("with List: result= " + genlnkPLCworkingwith[item]);
}
//foreach (string item in genlnkPLCCanvas) genlnkPLCworkingwith[item] = String.Format(item, i_Num, 200);
Console.ReadKey();
}
}
If you want to modify the existing list, you have to use for loop instead of foreach one:
foreach (var item in list) ...
should be changed into
for (int i = 0; i < list.Count; ++i) {
var item = list[i]; // not necessary, but often convenient
...
list[i] = ... // modification
...
}
For instance
for (int i = 0; i < genlnkPLCCanvas.Count; ++i) {
var item = genlnkPLCCanvas[i];
genlnkPLCCanvas[i] = string.Format(item, i_StationNum, 200);
}
When testing try creating reports (put all the logic into the single readable query) and then printing them out in one go:
...
var withListReport = genlnkPLC
.Select(item => "with List: result = " + string.Format(item, i_StationNum, 200));
var withoutListReport = genlnkPLC
.Select(item => "without List: result = " + string.Format(item, i_StationNum, 200));
// now you can do whatever you want with the reports:
// - print them to console
// Console.WriteLine(string.Join(Envrironment.NewLine, withListReport));
// - save to file:
// File.WriteAllLines(#"C:\MyFile.txt", withListReport);
// - print to, say, WinForm UI:
// MyTextBox.Text = string.Join(Envrironment.NewLine, withListReport);
Console.WriteLine(string.Join(Envrironment.NewLine, withListReport));
Console.WriteLine(string.Join(Envrironment.NewLine, withoutListReport));
Console.ReadKey();
String.Format() returns a string, it doesn't change whatever you're formatting. Therefore, your first foreach (var item in genlnkPLC) creates temporary strings that are immediately destroyed.
foreach (var item in genlnkPLC)
{
Console.WriteLine("with List = " + String.Format(item, i_StationNum, 200));
}
In the statement
foreach (var item in genlnkPLC)
Console.WriteLine("with List: result= "+item);
you are not using String.Format to insert arguments into the members of genlnkPLC, which are apparently intended as format strings. You can use
foreach (var item in genlnkPLC)
Console.WriteLine("without List result = " + String.Format(item, i_StationNum, 200));
instead.
The problem is that you can't change the reference of the elements enumerated in a foreach loop. string is an inmutable object, so changing it replaces the old reference with a new one. If you want to change the elements in the list, you'll need to do it in a for loop, like this:
for (int item = 0; item < genlnkPLC.Count; item++)
genlnkPLC[item]= String.Format(genlnkPLC[item], i_StationNum, 200);
No need to repeat foreach (the first one, did nothing to your item). Try this:
foreach (var item in genlnkPLC)
Console.WriteLine("with List: result= "+ String.Format(item, i_StationNum, 200));
As M.Bychenko says: "If you want to modify the existing list, you have to use for loop instead of foreach one:"
And thanks for the report tipp!
class Program
{
static void Main(string[] args)
{
int i_Num = 0;
string Str_Num = "";
string[] linkToPLC = {"toto[{0}].test{1}", "tata[{0}].test{1}", "titi[{0}].test{1}"};
List<string> genlnkPLCCanvas = new List<string>(linkToPLC);
List<string> genlnkPLCworkingwith = new List<string>(linkToPLC);
Console.WriteLine("Insert Num: ");
Str_Num = Console.ReadLine();
i_Num = Convert.ToInt32(Str_Num);
for (int item = 0; item < genlnkPLCCanvas.Count; item++)
{
genlnkPLCworkingwith[item] = String.Format(genlnkPLCCanvas[item], i_Num, 200);
}
var CanvasListReport = genlnkPLCCanvas.Select(item => "Canvas List = " + item);
var WorkingListReport = genlnkPLCworkingwith.Select(item => "Working list = " + item);//string.Format(item, i_Num, 200));
// now you can do whatever you want with the reports:
// - print them to console
// Console.WriteLine(string.Join(Envrironment.NewLine, withListReport));
// - save to file: File.WriteAllLines(#"C:\MyFile.txt", withListReport);
// - print to, say, WinForm UI:
// MyTextBox.Text = string.Join(Envrironment.NewLine, withListReport)
Console.WriteLine(string.Join(Environment.NewLine, CanvasListReport));
Console.WriteLine(string.Join(Environment.NewLine, WorkingListReport));
Console.ReadKey();
}
}
This is because
String.Format(item, i_StationNum, 200)
doesn't change the string in the list.
You have to assign the String.Format result to your item.

I want to know the count of each item in a list

So, I have a list with votes.
List<string> Votes = new List<string>();
with a maximum of three diferent strings. And I want to get a count of them. this is in c#.
I've looked through earlier questions, but haven't found anything similar without the problem being way more complicated than mine.
sorry if this has already been answered
Eh, Linq like that?:
List<String> votes = new List<String>() {
"Yes", "No", "Yes", "No", "?"
};
...
String report = String.Join(Environment.NewLine, votes
.GroupBy(item => item)
.Select(chunk => String.Format("{0} votes, count {1}", chunk.Key, chunk.Count()))
);
Console.Write(report);
You can use GroupBy:
var voteGroups = Votes.GroupBy(s => s);
Now, if you want to know the count of each string use Enumerable.Count:
foreach(var voteGroup in voteGroups)
Console.WriteLine("Vote:{0} Count:{1}", voteGroup.Key, voteGroup.Count());
Another way is using ToLookup:
var voteLookup = Votes.ToLookup(s => s);
foreach (var voteGroup in voteLookup)
Console.WriteLine("Vote:{0} Count:{1}", voteGroup.Key, voteGroup.Count());
The lookup has it's advantages, it enables you to find specific elements like a dictionary. So you could get the "pepsi"-count in this way:
int pepsiCount = voteLookup["Pepsi"].Count();
This does not cause an exception if there is no such string in the list(count will be 0).
if you want to make it case insensitive, so treat "pepsi" and "Pepsi" as equal:
var voteLookup = Votes.ToLookup(s => s, StringComparer.InvariantCultureIgnoreCase);
Not the best code, but it works:
int count1 = 0;
int count2 = 0;
foreach (String answer in Votes)
{
if (answer == "yes")
{
count1++;
}
if (answer == "no")
{
count2++;
}
}
If you're just trying to get the total number of unique items in your list:
int count = (from x in lst select x).Distinct().Count();
If all you have is a List of strings, then you can just use the Count property.
List<string> Votes = new List<string>();
// populate list here
Console.WriteLine(Votes.Count);
Try this...
var l = new List();
l.Add("abcd");
l.Add("abcd123");
l.Add("abcd1234");
var d = l.ToDictionary<string,int>(k=>k, v=>v.Length);
var count = d["abcd"]; //result would be 4.

C#: Loop over Textfile, split it and Print a new Textfile

I get many lines of String as an Input that look like this. The Input is a String that comes from
theObjects.Runstate;
each #VAR;****;#ENDVAR; represents one Line and one step in the loop.
#VAR;Variable=Speed;Value=Fast;Op==;#ENDVAR;#VAR;Variable=Fabricator;Value=Freescale;Op==;#ENDVAR;
I split it, to remove the unwanted fields, like #VAR,#ENDVAR and Op==.
The optimal Output would be:
Speed = Fast;
Fabricator = Freescale; and so on.
I am able to cut out the #VAR and the#ENDVAR. Cutting out the "Op==" wont be that hard, so thats now not the main focus of the question. My biggest concern right now is,thatI want to print the Output as a Text-File. To print an Array I would have to loop over it. But in every iteration, when I get a new line, I overwrite the Array with the current splitted string. I think the last line of the Inputfile is an empty String, so the Output I get is just an empty Text-File. It would be nice if someone could help me.
string[] w;
Textwriter tw2;
foreach (EA.Element theObjects in myPackageObject.Elements)
{
theObjects.Type = "Object";
foreach (EA.Element theElements in PackageHW.Elements)
{
if (theObjects.ClassfierID == theElements.ElementID)
{
t = theObjects.RunState;
w = t.Replace("#ENDVAR;", "#VAR;").Replace("#VAR;", ";").Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
foreach (string s in w)
{
tw2.WriteLine(s);
}
}
}
}
This linq-query gives the exptected result:
var keyValuePairLines = File.ReadLines(pathInputFile)
.Select(l =>
{
l = l.Replace("#VAR;", "").Replace("#ENDVAR;", "").Replace("Op==;", "");
IEnumerable<string[]> tokens = l.Split(new[]{';'}, StringSplitOptions.RemoveEmptyEntries)
.Select(t => t.Split('='));
return tokens.Select(t => {
return new KeyValuePair<string, string>(t.First(), t.Last());
});
});
foreach(var keyValLine in keyValuePairLines)
foreach(var keyVal in keyValLine)
Console.WriteLine("Key:{0} Value:{1}", keyVal.Key, keyVal.Value);
Output:
Key:Variable Value:Speed
Key:Value Value:Fast
Key:Variable Value:Fabricator
Key:Value Value:Freescale
If you want to output it to another text-file with one key-value pair on each line:
File.WriteAllLines(pathOutputFile, keyValuePairLines.SelectMany(l =>
l.Select(kv => string.Format("{0}:{1}", kv.Key, kv.Value))));
Edit according to your question in the comment:
"What would I have to change/add so that the Output is like this. I
need AttributeValuePairs, for example: Speed = Fast; or Fabricator =
Freescale ?"
Now i understand the logic, you have key-value pairs but you are interested only in the values. So every two key-values belong together, the first value of a pair specifies the attibute and the second value the value of that attribute(f.e. Speed=Fast).
Then it's a little bit more complicated:
var keyValuePairLines = File.ReadLines(pathInputFile)
.Select(l =>
{
l = l.Replace("#VAR;", "").Replace("#ENDVAR;", "").Replace("Op==;", "");
string[] tokens = l.Split(new[]{';'}, StringSplitOptions.RemoveEmptyEntries);
var lineValues = new List<KeyValuePair<string, string>>();
for(int i = 0; i < tokens.Length; i += 2)
{
// Value to a variable can be found on the next index, therefore i += 2
string[] pair = tokens[i].Split('=');
string key = pair.Last();
string value = null;
string nextToken = tokens.ElementAtOrDefault(i + 1);
if (nextToken != null)
{
pair = nextToken.Split('=');
value = pair.Last();
}
var keyVal = new KeyValuePair<string, string>(key, value);
lineValues.Add(keyVal);
}
return lineValues;
});
File.WriteAllLines(pathOutputFile, keyValuePairLines.SelectMany(l =>
l.Select(kv=>string.Format("{0} = {1}", kv.Key, kv.Value))));
Output in the file with your single sample-line:
Speed = Fast
Fabricator = Freescale

Splitting a list<string> item and formatting it out

I have a List that is being filled with something like this in a loop:
myList.Add("john,smith,50,actor");
Obviously I just wrote the pure string, they are actually some variables. Now what I want to do is to export this to a text file using Stringbuilder and StringWriter which I think I can manage it (already did similar things).
So I want my textfile to look like this:
NAME SURNAME AGE WORK
john smith 50 actor
And so on. Can you help me figure out a foreach loop for this case?
const string Format = "{0,-10} {1,-10} {2,-10} {3,-10}";
var myList = new List<string>();
myList.Add("john,smithhh,50,actor");
myList.Add("a,b,c,d");
var res = myList.Select(i => i.Split(','));
Console.WriteLine(Format, "NAME", "SURNAME", "AGE", "WORK");
foreach (var line in res)
{
Console.WriteLine(Format, line[0], line[1], line[2], line[3]);
}
Output:
NAME SURNAME AGE WORK
john smithhh 50 actor
a b c d
Here is how can create a text file our or your List<string>:
var path = #"C:\test.txt";
var streamWriter = File.Exists(path) ? File.AppendText(path) : File.CreateText(path);
using (streamWriter)
{
streamWriter.WriteLine("NAME\tSURNAME\tAGE\tWORK");
foreach (string s in myList)
{
streamWriter.WriteLine(s.Replace(",", "\t"));
}
}
since you already have separator(","), so you can directly do the following for better performance, no need to convert:
var result = new StringBuilder();
result.AppendLine("NAME\tSURNAME\tAGE\tWORK");
myList.ForEach(i => result.AppendLine(i.Replace(",", "\t")));
System.IO.File.WriteAllText("foo.txt", result.ToString());
You could split them into strings like this:
String[] strings = myList[i].Split(',');
And then get them individually like this:
for(int i = 0; i < strings.Count; i++)
{
file.Write(strings[i] + " ");
}

foreach loop question

Is there any other shorter/more efficient way to check and see if it is the last item in my ListBox? The main goal here is basically to add the selected items to a label, and add a comma after every one but the last one. Any suggestions?
int sc = 0;
List<string> interestitems = new List<string>();
foreach (ListItem siitem in ListBox1.Items)
{
if (siitem.Selected == true)
{
interestitems.Add(siitem.Value.ToString());
}
}
foreach (string inteitem in interestitems)
{
Label1.Text += inteitem;
sc++;
if (sc < interestitems.Count)
{
Label1.Text += ",";
}
}
Instead of your second loop just use:
Label1.Text = string.Join("," , interestitems);
P.S.
if you're using .net 3.5, you need to pass an array of strings to string.Join(), then :
Label1.Text = string.Join("," , interestitems.ToArray());
EDIT:
If you want to completely avoid looping just do:
var selItems = ListBox1.Items.Cast<ListItem>()
.Where(item => item.Selected)
.Select(item => item.ToString());
Label1.Text = string.Join("," , selItems);
How about LINQ:
Label1.Text = string.Join(
",",
ListBox1.Items
.OfType<ListItem>()
.Where(item => item.Selected)
.Select(x => x.Value.ToString())
.ToArray()
);
You can replace all of your code with some LINQ:
Label1.Text = String.Join(", ",
ListBox1.Items.Cast<ListItem>()
.Where(i => i.Selected)
.Select(i => i.Value.ToString())
);
In .Net 3.5, you'll need to add .ToArray().
I believe you can do this:
interestitems.IndexOf(inteitem);
Altought it worked me with other item types, may give you an idea. I haven't checked if it works with strings.
The you just have to eliminate the last one, with the index check if it's the last ones with interestitems.Count
Why not just build up the string as you iterate during the first loop
var builder = new StringBuilder();
var first = true;
foreach (var item in ListBox1.Items) {
if (item.Selected) {
if (!first) {
builder.Append(", ");
}
first = false;
builder.Append(item.Value.ToString());
}
}
Label1.Text = builder.ToString();

Categories