Need to compare values produced from separate foreach loops - c#

I have two foreach loops, each of which loops through a text file, and gets the value of all of the values of the first two columns only (there are more than two columns in the text file, delimited by "|") and puts it in a string. I would like to compare the result of these foreach loops (the values that are output by the Response.Write statements) to see if the strings are equivalent or not. Any thoughts/suggestions appreciated.
protected void Page_Load(object sender, EventArgs e)
{
string textFile1 = #"C:\Test\Test1.txt";
string textFile2 = #"C:\Test\Test2.txt";
string[] textFile1Lines = System.IO.File.ReadAllLines(textFile1);
string[] textFile2Lines = System.IO.File.ReadAllLines(textFile2);
char[] delimiterChars = { '|' };
foreach (string line in textFile1Lines)
{
string[] words = line.Split(delimiterChars);
string column1And2 = words[0] + words[1];
Response.Write(column1And2);
}
foreach (string line in textFile2Lines)
{
string[] words = line.Split(delimiterChars);
string column1And2 = words[0] + words[1];
Response.Write(column1And2);
}
}

One way to compare the outputs would be storing the strings as you go, and then compare the results using SequenceEqual. Since the two loops are identical, consider making a static method out of them:
// Make the extraction its own method
private static IEnumerable<string> ExtractFirstTwoColumns(string fileName) {
return System.IO.File.ReadLines(fileName).Select(
line => {
string[] words = line.Split(delimiterChars);
return words[0] + words[1];
}
);
}
protected void Page_Load(object sender, EventArgs e)
// Use extraction to do both comparisons and to write
var extracted1 = ExtractFirstTwoColumns(#"C:\Test\Test1.txt").ToList();
var extracted2 = ExtractFirstTwoColumns(#"C:\Test\Test2.txt").ToList();
// Write the content to the response
foreach (var s in extracted1) {
Response.Write(s);
}
foreach (var s in extracted2) {
Response.Write(s);
}
// Do the comparison
if (extracted1.SequenceEqual(extracted2)) {
Console.Error.WriteLine("First two columns are different.");
}
}

I would simply compare in the same loop, using for instead of foreach:
protected void Page_Load(object sender, EventArgs e)
{
string textFile1 = #"C:\Test\Test1.txt";
string textFile2 = #"C:\Test\Test2.txt";
string[] textFile1Lines = System.IO.File.ReadAllLines(textFile1);
string[] textFile2Lines = System.IO.File.ReadAllLines(textFile2);
char[] delimiterChars = { '|' };
if (textFile1Lines.Count != textFile2Lines.Count)
{
// Do something since the line counts don't match
}
else
{
foreach (int i = 0; i < textFile1Lines.Count; i++)
{
string[] words1 = textFile1Lines[i].Split(delimiterChars);
string compareValue1 = words1[0] + words1[1];
string[] words2 = textFile2Lines[i].Split(delimiterChars);
string compareValue2 = words2[0] + words2[1];
if (!string.Equals(compareValue1, compareValue2))
{
// Do something
break; // Exit the loop since you found a difference
}
}
}
}

Related

How can I show only a part of a string in a combobox

Problem when files are being loaded in a combobox whose name starts the same way? I want to show only the first letter of the string that is separated by _
Screenshot
private void frm_main_Load(object sender, EventArgs e)
{
string path = #"C:\Meteo";
if (Directory.Exists(path))
{
listBox1.Items.Clear();
string[] files = Directory.GetFiles(path);
string[] dirs = Directory.GetDirectories(path);
foreach (string file in files)
{
listBox1.Items.Add(Path.GetFileName(file));
comboBox2.Items.Add(Path.GetFileName(file));
}
foreach (string dir in dirs)
{
listBox1.Items.Add(Path.GetFileName(path));
}
}
else
{
MessageBox.Show("Директорията Meteo не е октирта в системен диск 'C:\'");
Application.ExitThread();
}
}
If you want first letter "0_2019_01_23.dat" => "0" you may write:
var formattedName = Path.GetFileName(file).Split('_').First();
If your want to truncate "0_2019_01_23.dat" => "23.dat" you may write:
var formattedName = Path.GetFileName(file).Split('_').Last();
If you want to take various parts "0_2019_01_23.dat" => "2019_01" you may write:
var formattedName = string.Join("_", Path.GetFileName(file).Split('_').Skip(1).Take(2));
To change the order "0_2019_01_23.dat" => "23_2019" you may write:
var parts = Path.GetFileNameWithoutExtension(file).Split('_');
var formattedName = string.Join("_", new []{parts[3], parts[1]});

C# CSV to JSON per row

Major Edit: I am doing a bad job of explaining :(
I have two classes:
public class UserDefinitions// a list of 'Items', each'group of items belong to a user. I handle User logic elsewhere, and it works flawlessly.
{
public List<Item> items { get; set; }
}
public class Item //the User definitions. A user could have 1 or 15 of these. They would all be a single 'line' from the CSV file.
{
public string definitionKey { get; set; }
public string defName { get; set; }
public string defValue { get; set; }
}
Which I wanna build with a CSV File. I build this CSV File, so I make it using the same parameters every time.
I run SQL on my company's DB to generate results like so: http://i.imgur.com/gS1UJot.png
Then I read the file like so:
class Program
{
static void Main(string[] args)
{
var userData = new UserDefinitions();
var csvList = new List<Item>();
string json = "";
string fPath = #"C:\test\csvTest.csv";
var lines = File.ReadAllLines(fPath);
Console.WriteLine(lines);
List<string> udata = new List<string>(lines);
foreach (var line in udata)
{
string[] userDataComplete = line.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);// this cleans any empty cells from the CSV
csvList.Add(new Item { definitionKey = userDataComplete[1], defName = userDataComplete[2], defValue = userDataComplete[3] });
}
json = JsonConvert.SerializeObject(csvList); //everything below is for debugging/tracking progress
Console.WriteLine(json);
Console.ReadKey();
StreamWriter sw = new StreamWriter("C:\\test\\testjson.txt");
sw.WriteLine(json);
sw.Close();
}
}
This ALMOST does what I want. The output json is from the first 'column' of the csv data
[{"definitionKey":"uuid1","defName":"HairColor","defValue":"Brown"},{"definitionKey":"uuid1","defName":"HairColor","defValue":"Blonde"},{"definitionKey":"uuid1","defName":"HairColor","defValue":"Blue"}]
When using the screen shot as an example, the wanted output should be
[{"attributeDefinitionKey":"uuid1","name":"HairColor","value":"Brown"},{"definitionKey":"uuid2","defName":"FreckleAmount","defValue":"50"}]
[{"attributeDefinitionKey":"uuid1","name":"HairColor","value":"Blonde"},{"definitionKey":"uuid2","defName":"FreckleAmount","defValue":"null"}]
[{"attributeDefinitionKey":"uuid1","name":"HairColor","value":"Blue"},{"definitionKey":"uuid3","defName":"Tattoos","defValue":"5"}]
I can't pick out certain aspects at will, or apply them to Items. For example there maybe 10 users or 5000 users, but the definitionKey will always be the [1], and adding '3' will get every subsequent defintionKey. Just like the defName will always be in the [2] spot and adding 3 will get every subsequent defName if there are any, this is all per line.
I know I have to add some +3 logic, but not quite sure how to incorporate that. Maybe a for loop? a nested for loop after a foreach loop? I feel I am missing something obvious!
Thanks again for any help
This reads the csv line for line and converts each row to json, while adapting to the change in the amount of columns.
This only works if the CSV follows your rules:
one userId and
x amount of "Things" with 3 columns per "Thing".
private static void Main(string[] args)
{
var file = new StreamReader(#"C:\test\csvTest.csv");
string line;
var itemsJson = new List<string>();
file.ReadLine();
while ((line = file.ReadLine()) != null)
{
var sb = new StringBuilder();
var fields = line.Split(',');
sb.Append(GetKeyValueJson("UserId", fields[0]));
for (var i = 1; i < fields.Length; i += 3)
{
var x = (i + 3) / 3;
sb.Append(GetKeyValueJson($"Thing {i + x} ID", fields[i]));
sb.Append(GetKeyValueJson($"Thing {i + x} ID", fields[i + 1]));
sb.Append(i + 3 == fields.Length
? GetKeyValueJson($"Thing {i + x} ID", fields[i + 2], true)
: GetKeyValueJson($"Thing {i + x} ID", fields[i + 2]));
}
itemsJson.Add(WrapJson(sb.ToString()));
}
var json = WrapItems(itemsJson);
Console.ReadLine();
}
private static string GetKeyValueJson(string id, string value, bool lastPair = false)
{
var sb = new StringBuilder();
sb.Append('"');
sb.Append(id);
sb.Append('"');
sb.Append(':');
sb.Append('"');
sb.Append(value);
sb.Append('"');
if (!lastPair)
sb.Append(',');
return sb.ToString();
}
private static string WrapJson(string s)
{
var sb = new StringBuilder();
sb.Append('{');
sb.Append(s);
sb.Append('}');
return sb.ToString();
}
private static string WrapItems(List<string> jsonList)
{
var sb = new StringBuilder();
sb.Append('"');
sb.Append("Items");
sb.Append('"');
sb.Append(':');
sb.Append('[');
sb.Append(jsonList.Aggregate((current, next) => current + "," + next));
sb.Append(']');
return WrapJson(sb.ToString());
}
}
It's not pretty and sorting would be tough, but it should adapt to the column amount as long as it is in 3's.

How can i ignore replace text within specific two symbol

I used following code snippet to replace text
private void textBox1_TextChanged(object sender, EventArgs e)
{
string A = textBox1.Text.Trim();
string B = textBox1.Text.Trim();
A = A.Replace("AB", "CD");
A = A.Replace("GF", "HI");
A = A.Replace("AC", "QW");
A = A.Replace("VB", "GG");
textBox2.Text = (A);
}
but i wants to ignore this replace technique within || these symbol.As a example my code do this
when i type AB GF in a txtbox1,txtbox2 replace as following CD HI.
Now i need when i type |AB GF| in txtbox1 ,txtbox2 replace as AB GF
i used this code to do this
textBox2.Text = ((B.Contains("|")) ? B.Replace("|", "") : A);
but this isn't work,after | this symbol all containing things in txtbox1 not replaced,how can i do this
Per your comments, you will want to split your string on the spaces prior to doing the replacement. Afterwards you will join it all back together. This is pretty easy with Linq.
public Main()
{
var strings = new string[]{ "AB GF", "|AB| GF" };
foreach (var s in strings)
Console.WriteLine(String.Join(" ", s.Split(' ').Select(x => ReplaceText(x))));
}
string ReplaceText(string text)
{
if (text.Contains("|"))
return text.Replace("|", String.Empty);
else
{
text = text.Replace("AB", "CD");
text = text.Replace("GF", "HI");
text = text.Replace("AC", "QW");
return text.Replace("VB", "GG");
}
}
Prints:
CD HI
AB HI
Looking at your code. If you need to avoid a ReplaceText method. Something like this would work.
string A = textBox1.Text.Trim();
var subStrings = A.Split(' ');
for (int i = 0; i < subStrings.Count(); i++)
{
if (subStrings[i].Contains("|"))
subStrings[i] = subStrings[i].Replace("|", String.Empty);
else
{
subStrings[i] = subStrings[i].Replace("AB", "CD");
subStrings[i] = subStrings[i].Replace("GF", "HI");
subStrings[i] = subStrings[i].Replace("AC", "QW");
subStrings[i] = subStrings[i].Replace("VB", "GG");
}
}
textBox2.Text = String.Join(" ", subStrings);

Split and Join problems

I split them to get first letter to be upper case now I'm having problem merging them and the first letters are still upper cased. Also my data is from a database
private void button1_Click(object sender, EventArgs e)
{
//input = input.Replace("_", "");
string input;
input = table_menu.Text;
string[] words = input.Split('_');
foreach (string word in words)
{
string nword = word.First().ToString().ToUpper() + String.Join("", word.Skip(1));
string merge = String.Join("", nword);
MessageBox.Show(merge);
}
label1.Text = input.First().ToString().ToUpper() + String.Join("", input.Skip(1));
Console.WriteLine(label1.Text);
}
Current Ouput: tablepatient
I want a out to be like this:
TablePatient
The concept of capitalization is culture-specific - capitalization in one culture may not be the same as capitalization in another. If you are serializing your strings to XML for persistent storage, you probably want to use the invariant culture; if you are showing them to a user, then the local culture (or maybe the local UI culture) is appropriate.
That being said, the following probably do the job:
public static string UnderscoreToTitleCase(string input)
{
return UnderscoreToTitleCase(input, System.Globalization.CultureInfo.CurrentCulture);
}
public static string UnderscoreToTitleCaseInvariant(string input)
{
return UnderscoreToTitleCase(input, System.Globalization.CultureInfo.InvariantCulture);
}
public static string UnderscoreToTitleCase(string input, CultureInfo cultureInfo)
{
string[] words = input.Split('_');
StringBuilder sb = new StringBuilder();
foreach (string word in words)
sb.Append(cultureInfo.TextInfo.ToTitleCase(word));
return (sb.ToString());
}
private void button1_Click(object sender, EventArgs e)
{
string input;
input = table_menu.Text;
string[] words = input.Split('_');
StringBuilder sb = new StringBuilder();
foreach (string word in words)
{
string nword = word.First().ToString().ToUpper() + String.Join("", word.Skip(1));
string merge = String.Join("", nword);
MessageBox.Show(merge);
sb.Append(nword);
}
label1.Text = sb.ToString();
Console.WriteLine(label1.Text);
}
This works:
var input = "table_patient";
var output = String.Join("",
input
.Split('_')
.Where(x => !String.IsNullOrEmpty(x))
.Select(x => new string(
x
.Take(1)
.Select(c => char.ToUpperInvariant(c))
.Concat(x.Skip(1))
.ToArray())));
//output == "TablePatient"
This also works:
var output = System
.Globalization
.CultureInfo
.CurrentCulture
.TextInfo
.ToTitleCase(input)
.Replace("_", "");

How to remove duplicates from List<string> without LINQ? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Remove duplicates from a List<T> in C#
i have a List like below (so big email list):
source list :
item 0 : jumper#yahoo.com|32432
item 1 : goodzila#yahoo.com|32432|test23
item 2 : alibaba#yahoo.com|32432|test65
item 3 : blabla#yahoo.com|32432|test32
the important part of each item is email address and the other parts(separated with pipes are not important) but i want to keep them in final list.
as i said my list is to big and i think it's not recommended to use another list.
how can i remove duplicate emails (entire item) form that list without using LINQ ?
my codes are like below :
private void WorkOnFile(UploadedFile file, string filePath)
{
File.SetAttributes(filePath, FileAttributes.Archive);
FileSecurity fSecurity = File.GetAccessControl(filePath);
fSecurity.AddAccessRule(new FileSystemAccessRule(#"Everyone",
FileSystemRights.FullControl,
AccessControlType.Allow));
File.SetAccessControl(filePath, fSecurity);
string[] lines = File.ReadAllLines(filePath);
List<string> list_lines = new List<string>(lines);
var new_lines = list_lines.Select(line => string.Join("|", line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries)));
List<string> new_list_lines = new List<string>(new_lines);
int Duplicate_Count = 0;
RemoveDuplicates(ref new_list_lines, ref Duplicate_Count);
File.WriteAllLines(filePath, new_list_lines.ToArray());
}
private void RemoveDuplicates(ref List<string> list_lines, ref int Duplicate_Count)
{
char[] splitter = { '|' };
list_lines.ForEach(delegate(string line)
{
// ??
});
}
EDIT :
some duplicate email addrresses in that list have different parts ->
what can i do about them :
mean
goodzila#yahoo.com|32432|test23
and
goodzila#yahoo.com|asdsa|324234
Thanks in advance.
say you have a list of possible duplicates:
List<string> emailList ....
Then the unique list is the set of that list:
HashSet<string> unique = new HashSet<string>( emailList )
private void RemoveDuplicates(ref List<string> list_lines, ref int Duplicate_Count)
{
Duplicate_Count = 0;
List<string> list_lines2 = new List<string>();
HashSet<string> hash = new HashSet<string>();
foreach (string line in list_lines)
{
string[] split = line.Split('|');
string firstPart = split.Length > 0 ? split[0] : string.Empty;
if (hash.Add(firstPart))
{
list_lines2.Add(line);
}
else
{
Duplicate_Count++;
}
}
list_lines = list_lines2;
}
The easiest thing to do is to iterate through the lines in the file and add them to a HashSet. HashSets won't insert the duplicate entries and it won't generate an exception either. At the end you'll have a unique list of items and no exceptions will be generated for any duplicates.
1 - Get rid of your pipe separated string (create an dto class corresponding to the data it's representing)
2 - which rule do you want to apply to select two object with the same id ?
Or maybe this code can be useful for you :)
It's using the same method as the one in #xanatos answer
string[] lines= File.ReadAllLines(filePath);
Dictionary<string, string> items;
foreach (var line in lines )
{
var key = line.Split('|').ElementAt(0);
if (!items.ContainsKey(key))
items.Add(key, line);
}
List<string> list_lines = items.Values.ToList();
First, I suggest to you load the file via stream.
Then, create a type that represent your rows and load them into a HashSet(for
performance considerations).
Look (Ive removed some of your code to make it simple):
public struct LineType
{
public string Email { get; set; }
public string Others { get; set; }
public override bool Equals(object obj)
{
return this.Email.Equals(((LineType)obj).Email);
}
}
private static void WorkOnFile(string filePath)
{
StreamReader stream = File.OpenText(filePath);
HashSet<LineType> hashSet = new HashSet<LineType>();
while (true)
{
string line = stream.ReadLine();
if (line == null)
break;
string new_line = string.Join("|", line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries));
LineType lineType = new LineType()
{
Email = new_line.Split('|')[3],
Others = new_line
};
if (!hashSet.Contains(lineType))
hashSet.Add(lineType);
}
}

Categories

Resources