I'm having some issues with the following:
I have a txt file with roughly two thousand names, with a bunch of duplicate entries. I'm trying to create something where it will list the amount of times a name appears. So for example:
John Doe | 48 times
Jane Doe | 20 times
etc etc.
I found examples here on how i could count this, but i have absolutely no idea how i could have this output this to a richTextbox or other file for example.
.Select(s => new { Key = s.Key, Count = s.Count()})
.ToDictionary(d => d.Key, d => d.Count);```
Data enter into the file names.txt file.
John Deo
John Deo
John Deo
John wick
John wick
Testing
Testing
I have made file into the project called names.txt and read him in code which are below.
string[] lines = File.ReadAllLines("../../names.txt");
Then grouping the names and print into the console application.
var mylines = lines.GroupBy(g => g).Select(s => new { Name = s, Count = s.Count() });
foreach (var line in mylines)
{
Console.WriteLine($"{line.Name.Key} | {line.Count}");
}
Result#
John Deo | 11
John wick | 2
Testing | 5
There are many different ways to do this. If all you want is to determine the counts and how it's displayed doesn't matter then you could output the counts to a CSV file and look at it with Excel. I don't know exactly how your names are formatted in the simple example below I assume one name per line.
class Program
{
static void Main(string[] args)
{
try
{
using (var reader = new StreamReader("names.txt"))
{
var names = GetNames(reader).ToLookup(k => k);
using (var writer = new StreamWriter("names.counted.csv"))
{
foreach (var name in names)
{
writer.WriteLine($"{name.Key},{name.Count()}");
}
}
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.ToString());
}
}
static IEnumerable<string> GetNames(TextReader reader)
{
string line;
while ((line = reader.ReadLine()) != null)
yield return line;
}
}
Assumption:
Lets say we already have each line of the text file in an List<string> object we will call names and that each line in the text file represents a whole name spelled correctly.
Grouping/Printing the data:
Using LINQ we can group these values by themselves (similar to SQL) and then convert the IGrouping results into the objects we want to use later in our application. For example:
var totals = names.GroupBy(x => x)
.Select(group => new { Name = group.Key, Count = group.Count() });
foreach ( var total in totals )
{
Console.WriteLine($"{total.Name} | {total.Count} times");
}
Another option would be to use your existing code and just print out the values of the dictionary
var totals = names
.Select(s => new { Key = s.Key, Count = s.Count()})
.ToDictionary(d => d.Key, d => d.Count);
foreach ( var kvp in totals )
{
Console.WriteLine($"{kvp.Key} | {kvp.Value} times");
}
Saving/Displaying the data:
If you want to do something other then print to console you could simply manipulate the data into the value you want. For example if you want to save it to another file:
var csvContent = totals
.Select(total => $"{total.Name},${total.Count} times")
.ToArray();
File.WriteAllLines(filePath, csvContent);
Or you could create a string (e.g. in above: String.Join("\n", csvContent)) and update a RichTextBox like so
You could iterate over the results of your query and add each name/count to a StringBuilder, then output the final string to your RichTextBox:
StringBuilder sb = new StringBuilder();
foreach(var KVP in yourDictionaryVariableName)
{
sb.AppendLine(KVP.Key + " | " + KVP.Value.ToString());
}
richTextBox1.Text = sb.ToString();
Related
i need to sort and display my code by ascending order based off on the item number. Here's the sample code.
string data = $"{itemNumber}|{itemName}|{itemPrice}";
using (StreamWriter writer = File.AppendText("items.txt"))
{
writer.WriteLine(data);
}
public void DisplayItemList()
{
using (StreamReader reader = new StreamReader("items.txt"))
{
Console.WriteLine("\n ---------------------------------");
Console.WriteLine(" Item No. Item Name Price");
Console.WriteLine(" ---------------------------------");
while (!reader.EndOfStream)
{
string line = reader.ReadLine();
string[] fields = line.Split('|');
Console.WriteLine(String.Format(" {0,-13}{1,-16}{2,0}", fields[0], fields[1], fields[2]));
}
Console.Write("\n");
}
}
here's my sample code. as you can see i have
1 - oslopaper | 34 - bond | 11 - art
I needed it to be
1 - oslopaper, 11 - art, lastly, 34 - bond
because I wanted it to be in ascending order.
I suggest quering file with a help of Linq (here you can add ordering - OrderBy; representing - Select, headers - Prepend):
using System.Linq;
using System.IO;
...
public void DisplayItemList() {
var result = File
.ReadLines("items.txt")
.Where(line => !string.IsNullOrWhiteSpace(line)) // to be on the safer side
.Select(line => line.Split('|'))
.OrderBy(fields => int.Parse(fields[0]))
.Select(fields => $" {fields[0],-13}{fields[1],-16}{fields[2],0}")
.Prepend(" --------------------------------- ")
.Prepend(" Item No. Item Name Price ")
.Prepend(" --------------------------------- ");
Console.Write(string.Join(Environment.NewLine, result));
}
you can sort items before displaying them by LINQ
var lines = File.ReadAllLines("items.txt").OrderBy(line => int.Parse(line.Split('|')[0]));
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
I have a folder with pictures:
Folder 1:
Files:
ABC-138923
ABC-3223
ABC-33489
ABC-3111
CBA-238923
CBA-1313
CBA-1313
DAC-38932
DAC-1111
DAC-13893
DAC-23232
DAC-9999
I want to go through this folder and count how many of each picture pre-fix I have.
For example, there are 4 pictures of pre-fix ABC and 3 pictures of pre-fix CBA above.
I'm having a hard time trying to figure out how to loop through this. Anyone can give me a hand?
Not a loop, but more clear and readable:
string[] fileNames = ...; //some initializing code
var prefixes = fileNames.GroupBy(x => x.Split('-')[0]).
Select(y => new {Prefix = y.Key, Count = y.Count()});
Upd:
To display the count for each prefix:
foreach (var prefix in prefixes)
{
Console.WriteLine("Prefix: {0}, Count: {1}", prefix.Prefix, prefix.Count);
}
Here it is with a 'foreach' loop:
var directoryPath = ".\Folder1\";
var prefixLength = 3;
var accumulator = new Dictionary<string, int>();
foreach (var file in System.IO.Directory.GetFiles(directoryPath)) {
var prefix = filefile.Replace(directoryPath, string.Empty).Substring(0, prefixLength);
if (!accumulator.ContainsKey(prefix))
{
accumulator.Add(prefix, 0);
}
accumulator[prefix]++;
}
foreach(var prefix in accumulator.Keys) {
Console.WriteLine("{0}: {1}", prefix, accumulator[prefix]);
}
in C#,
using System.IO;
using System.Collections.Generic;
...
DirectoryInfo dir = new DirectoryInfo("C:\\yourfolder");
FileInfo[] files = dir.GetFiles();
List<string> prefix = new List<string>();
List<int> count = new List<int>();
foreach (FileInfo file in files)
{
if (prefix.Count > 0)
{
Boolean AddNew = true;
for (int i = 0; i < prefix.Count; i++)
{
if (file.Name.Substring(0, 3) == prefix[i])
{
count[i]++;
AddNew = false;
}
}
if (AddNew)
{
prefix.Add(file.Name.Substring(0, 3));
count.Add(1);
}
}
else
{
prefix.Add(file.Name.Substring(0, 3));
count.Add(1);
}
}
...
The prefix string list is parallel to the count list, so to access you could loop through the array. I haven't tested or optimized it, but if you're heading down this route (c#) this could be a start.
The algorithm:
Create a dictionary:
Dictionary<string, int> D;
Loop through the directory using:
foreach (var file in System.IO.Directory.GetFiles(dir))
...
Complete the following 3 steps for each file:
Extract the prefix and see if a matching key exists in D. If TRUE, go to step 3.
Insert the prefix as a new key in D, with value 0
Increment the key's value by 1
To display results when the entire directory has been processed:
foreach (KeyValuePair<string, int> pair in D)
Console.WriteLine("{0} prefix has {1} files", pair.Key, pair.Value);
Text File:
$3.00,0.00,0.00,1.00,L55894M8,$3.00,0.00,0.00,2.00,L55894M9
How do I split the line and get the serial number like L55894M8 and L55894M9?
To get the data that appears after the 4th comma and 9th comma, you would want to do:
var pieces = line.Split(',');
var serial1 = line[3];
var serial2 = line[8];
Edit: Upon further reflection, it appears your file has records that begin with $ and end with the next record. If you want these records, along with the serial number (which appears to be the last field) you can do:
var records = line.TrimStart('$').Split('$');
var recordObjects = records.Select(r => new { Line = r, Serial = r.TrimEnd(',').Split(',').Last() });
In your sample you means want to get the words in index of ( 4 , 9 , 14 .... )
And the five words as a party .
So you can try this way.....
static void Main(string[] args)
{
string strSample = "$3.00,0.00,0.00,1.00,L55894M8,$3.00,0.00,0.00,2.00,L55894M9";
var result = from p in strSample.Split(',').Select((v, i) => new { Index = i, Value = v })
where p.Index % 5 == 4
select p.Value;
foreach (var r in result)
{
Console.WriteLine(r);
}
Console.ReadKey();
}
if the file is in a string you can use the string's .split(',') method then check each element of the resulting array. Or grab every 5th element if that pattern of data is seen throughout.
var str = "$3.00,0.00,0.00,1.00,L55894M8,$3.00,0.00,0.00,2.00,L55894M9";
var fieldArray = str.Split(new[] { ',' });
var serial1 = fieldArray[4]; // "L55894M8"
var serial2 = fieldArray[9]; // "L55894M9"
Try regular expression.
string str = "$3.00,0.00,0.00,1.00,L55894M8,$3.00,0.00,0.00,2.00,L55894M9";
string pat = #"L[\w]+";
MatchCollection ar= Regex.Matches(str, pat);
foreach (var t in ar)
Console.WriteLine(t);
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] + " ");
}