Reputation: 114
I'm trying to do something pretty specific with lists and counting unique instances, then saving that on a new line in a file.
Essentially, I have a listview with a set of columns, I want to loop through the whole list, and save a count of each unique item.
Example, a list like so;
111
222
111
333
333
333
would end up being written to file as:
111:2
222:1
333:3
I dont need it to be in any particular order, just so long as I have those values.
So far I have this;
string fileName = Application.StartupPath + @"\txn_" +
TerminalConfig.CreateSafSig() + ".saf";
Dictionary<string, int> products = new Dictionary<string, int>();
List<string> codes = new List<string>();
foreach (ListViewItem item in BasketList.Items)
{
codes.Add(item.SubItems[3].Text);
}
String[] items = codes.ToArray();
foreach (String code in items)
{
if (products.ContainsKey(code) != true)
{
products.Add(code, 1);
}
else
{
products[code] += 1;
}
}
foreach (var entry in products)
{
File.WriteAllText(fileName, string.Format("{0}:{1}",entry.Key,entry.Value));
}
But the file it saves is only giving me what would be the last line.
in the example above, it would only show 333:3
I was pretty sure I wrote it correctly, and I'm struggling to find where I've gone wrong.
Upvotes: 1
Views: 429
Reputation: 29981
Harrison answered why your code is not working... now let me show you why Jonesy (rudely) suggested you use GroupBy...
File.WriteAllLines(fileName,
from item in BasketList.Items
group item by item.SubItems[3].Text into grp
select string.Format("{0}:{1}", grp.Key, grp.Count()));
This effectively replaces all of your code. It is less efficient -- GroupBy
creates groups of the items when really you only need a count, so it is a bit heavyweight on memory usage -- but that isn't often a hugely important factor. There is something to be said about being succinct.
Upvotes: 2
Reputation: 70523
The problem is you overwrite the file with every iteration of the loop.
Code fix:
StringBuilder str = new StringBuilder();
foreach (var entry in products)
{
str.AppendLine(string.Format("{0}:{1}", entry.Key, entry.Value));
}
File.WriteAllText(fileName, str.ToString()); }
To jump on the linq bandwagon here is the code to make a dictionary:
Dictionary<string, int> products =
BasketList.Items.GroupBy(element => element.SubItems[3].Text)
.ToDictionary(k => k.Key, c => c.Count())
Yes in linq that replaces all those lines in one.
Upvotes: 2
Reputation: 3953
File.WriteAllText
writes a new file. You are overwriting the file each time you iterate through your for loop giving you only the last line.
The msdn page shows
Creates a new file, write the contents to the file, and then closes the file. If the target file already exists, it is overwritten.
You could replace the File.WriteAllText
with File.AppendAllText
which:
Opens a file, appends the specified string to the file, and then closes the file. If the file does not exist, this method creates a file, writes the specified string to the file, then closes the file.
If you want to write the file all at once, you could use File.WriteAllLines(string path,IEnumerable<string> contents)
; which
Creates a new file, writes a collection of strings to the file, and then closes the file.
In your case replace :
foreach (var entry in products)
{
File.WriteAllText(fileName, string.Format("{0}:{1}",entry.Key,entry.Value));
}
with
var entries = from entry in products select string.Format("{0}:{1}",entry.Key,entry.Value);
File.WriteAllLines(fileName,entries);
Upvotes: 4
Reputation: 511
The WriteAllText function will overwrite the file contents with the string you supply. You should use the AppendAllText function instead
Upvotes: 0