How to efficiently edit data within a C# String Array - c#

I'm working on a simple program to edit data within a string array, and have been scratching my head over this for the past few nights. I'm relatively new to C# and would really appreciate some help.
I want to edit a string array into something that looks like this (in theory):
[Section]
Key: Data
Key2: Data
Key3: Data
If the section isn't found, it should be created (along with another line containing the key & data passed to the method). If it is found, it should be checked until the next section (or the end of the file). If the key is not found within the section, it should be created at the end of the section. If it is found, the data of the key should be edited.
What's the best way of doing this? I've tried a few times with some super hacky code and always wind up with something like this:
[Section]
Key3: System.String[]
Sorry if this isn't the best question. I'm relatively new to C#, as I've said, and could really use the help. Thanks.

"edit data within a string array"
string[] myArray = { "one", "two", "three" };
myArray[1] = "nottwo";
Second value (myArray[1]) has changed from two to nottwo.
Now going deeper into the description of your problem...
You have mentioned keys & values, for this you will very likely want to look into Dictionary<TKey,TValue> Class. See reference: https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?view=netframework-4.8
Example:
Dictionary<int, string> myDictionary = new Dictionary<string, string>();
myDictionary.Add("one", "Hello");
myDictionary.Add("two", "World");
myDictionary.Add("three", "This is");
myDictionary.Add("sandwich", "a Dictionary.");
Console.Writeline(myDictionary["one"]);
Console.Writeline(myDictionary["two"]);
Console.Writeline(myDictionary["three"]);
Console.Writeline(myDictionary["sandwich"]);

I've found some code that works for my use case.
public static string[] SetData(string section, string key, string value, string[] data)
{
var updatedData = data;
int sectionIndex = Array.IndexOf(data, "[" + section + "]");
if(sectionIndex > -1)
{
//section found
for(int i = sectionIndex; i < data.Length; i++)
{
if (data[i].StartsWith(key))
{
//key found
string newData = data[i];
string tempString = newData.Remove(newData.LastIndexOf(":"));
updatedData[i] = tempString + ": " + value;
break;
}
else if (data[i].StartsWith("[") && !data[i].Contains(section))
{
//key not found, end of section reached.
List<string> temp = data.ToList();
temp.Insert(i, key + ": " + value);
updatedData = temp.ToArray();
break;
}
else if (i == data.Length - 1) //-1?
{
//key not found, end of file reached.
List<string> temp = data.ToList();
temp.Insert(i, key + ": " + value);
updatedData = temp.ToArray();
break;
}
}
return updatedData;
}
else
{
//section not found
updatedData = new string[data.Length + 2];
for (int i = 0; i < data.Length; i++)
{
updatedData[i] = data[i];
}
updatedData[updatedData.Length - 2] = "[" + section + "]";
updatedData[updatedData.Length - 1] = key + ": " + value;
return updatedData;
}
}

Related

Duplicates using Arrays and TextFile

I'm having an issue outputting my current code in Unity. I'm using an output text field to display the amount of duplicates per number.
Been browsing feeds and haven't gotten what I needed so here I am asking this now.
public int whatIndex,count;
public Text output;
public void Start()
{
string Random = "";
//reading the text file
string Duplicates = "duplicates.txt";
string Duplicates_Path = Application.dataPath + "/Text_Files/" + Duplicates;
string[] Numbers = File.ReadAllLines(Duplicates_Path);
foreach(string number in Numbers)
{
Random += number;
}
output.text = Random + "\n";
//array for text
for (whatIndex = 0; whatIndex < Duplicates.Length; whatIndex++)
{
Debug.Log(Numbers[whatIndex] + "\n");
Debug.Log("The number " + Numbers[whatIndex].ToString() + " appears " + count +
" times(s)");
}
}
As I understand you want to count occurrence for each number which is available in duplicate.txt files. Please find below code, i have tweak your code little bit e.g. file path and debug.log and remove unnecessary variables. you can see input here and output here:
public void Start()
{
Dictionary<int, int> numberCount = new Dictionary<int, int>();
//reading the text file
string Duplicates = "duplicates.txt";
string Duplicates_Path = Environment.CurrentDirectory + "\\Text_Files\\" + Duplicates;
string[] Numbers = File.ReadAllLines(Duplicates_Path);
foreach (string number in Numbers)
{
int temp = int.Parse(number);
if (numberCount.ContainsKey(temp))
{
numberCount[temp] = numberCount[temp] + 1;
}
else
{
numberCount[temp] = 1;
}
}
//array for text
foreach(KeyValuePair<int,int> item in numberCount)
{
Console.WriteLine("The number " + item.Key.ToString() + " appears " + item.Value.ToString() +
" times(s)");
}
}
I am not sure, what you want to achieve but I guess, there are some problems with your code (see after code).
Example Snippet:
First of all, you can try to use this code to get an idea about one solution to get the duplicates and the number of duplicates after reading the text file by using a Dictionary from System.Collections.Generic:
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
// String array with duplicates
string[] Numbers = {"1","1", "2", "6","1","7","1","7","8","3"};
Dictionary<string, int> KeyNumbersValueCount = new Dictionary<string, int>();
foreach(string number in Numbers)
{
if(KeyNumbersValueCount.ContainsKey(number))
KeyNumbersValueCount[number] += 1;
else
KeyNumbersValueCount.Add(number, 1);
}
foreach(var NumberAndCount in KeyNumbersValueCount)
Console.WriteLine("The number " + NumberAndCount.Key + " appears " +
NumberAndCount.Value + " times(s)");
}
}
running example code above
Open Issues with your code from the question:
Do you need count? It is initializied but never used
If you don't need "whatIndex", then you can also initialize it within the for loop:
for (int whatIndex = 0; whatIndex < Duplicates.Length; whatIndex++)
{
// do s.th.
}
You are trying to iterate over length of the string "Duplicates", which is "duplicates.txt" and therefore it has a length of 14. I guess you want to iterate over your strings in your file.
In your case, Random doesn't really have a function. You could also use File.ReadAllText instead of File.ReadAllLines and hand it over to output.text, if you only want to print it. See Microsoft Refs.

How to parse below string in C#?

Please someone to help me to parse these sample string below? I'm having difficulty to split the data and also the data need to add carriage return at the end of every event
sample string:
L,030216,182748,00,FF,I,00,030216,182749,00,FF,I,00,030216,182750,00,FF,I,00
batch of events
expected output:
L,030216,182748,00,FF,I,00 - 1st Event
L,030216,182749,00,FF,I,00 - 2nd Event
L,030216,182750,00,FF,I,00 - 3rd Event
Seems like an easy problem. Something as easy as this should do it:
string line = "L,030216,182748,00,FF,I,00,030216,182749,00,FF,I,00,030216,182750,00,FF,I,00";
string[] array = line.Split(',');
StringBuilder sb = new StringBuilder();
for(int i=0; i<array.Length-1;i+=6)
{
sb.AppendLine(string.Format("{0},{1} - {2} event",array[0],string.Join(",",array.Skip(i+1).Take(6)), "number"));
}
output (sb.ToString()):
L,030216,182748,00,FF,I,00 - number event
L,030216,182749,00,FF,I,00 - number event
L,030216,182750,00,FF,I,00 - number event
All you have to do is work on the function that increments the ordinals (1st, 2nd, etc), but that's easy to get.
This should do the trick, given there are no more L's inside your string, and the comma place is always the sixth starting from the beginning of the batch number.
class Program
{
static void Main(string[] args)
{
String batchOfevents = "L,030216,182748,00,FF,I,00,030216,182749,00,FF,I,00,030216,182750,00,FF,I,00,030216,182751,00,FF,I,00,030216,182752,00,FF,I,00,030216,182753,00,FF,I,00";
// take out the "L," to start processing by finding the index of the correct comma to slice.
batchOfevents = batchOfevents.Substring(2);
String output = "";
int index = 0;
int counter = 0;
while (GetNthIndex(batchOfevents, ',', 6) != -1)
{
counter++;
if (counter == 1){
index = GetNthIndex(batchOfevents, ',', 6);
output += "L, " + batchOfevents.Substring(0, index) + " - 1st event\n";
batchOfevents = batchOfevents.Substring(index + 1);
} else if (counter == 2) {
index = GetNthIndex(batchOfevents, ',', 6);
output += "L, " + batchOfevents.Substring(0, index) + " - 2nd event\n";
batchOfevents = batchOfevents.Substring(index + 1);
}
else if (counter == 3)
{
index = GetNthIndex(batchOfevents, ',', 6);
output += "L, " + batchOfevents.Substring(0, index) + " - 3rd event\n";
batchOfevents = batchOfevents.Substring(index + 1);
} else {
index = GetNthIndex(batchOfevents, ',', 6);
output += "L, " + batchOfevents.Substring(0, index) + " - " + counter + "th event\n";
batchOfevents = batchOfevents.Substring(index + 1);
}
}
output += "L, " + batchOfevents + " - " + (counter+1) + "th event\n";
Console.WriteLine(output);
}
public static int GetNthIndex(string s, char t, int n)
{
int count = 0;
for (int i = 0; i < s.Length; i++)
{
if (s[i] == t)
{
count++;
if (count == n)
{
return i;
}
}
}
return -1;
}
}
Now the output will be in the format you asked for, and the original string has been decomposed.
NOTE: the getNthIndex method was taken from this old post.
If you want to split the string into multiple strings, you need a set of rules,
which are implementable. In your case i would start splitting the complete
string by the given comma , and than go though the elements in a loop.
All the strings in the loop will be appended in a StringBuilder. If your ruleset
say you need a new line, just add it via yourBuilder.Append('\r\n') or use AppendLine.
EDIT
Using this method, you can also easily add new chars like L or at the end rd Event
Look for the start index of 00,FF,I,00 in the entire string.
Extract a sub string starting at 0 and index plus 10 which is the length of the characters in 1.
Loop through it again each time with a new start index where you left of in 2.
Add a new line character each time.
Have a try the following:
string stream = "L,030216,182748,00,FF,I,00, 030216,182749,00,FF,I,00, 030216,182750,00,FF,I,00";
string[] lines = SplitLines(stream, "L", "I", ",");
Here the SplitLines function is implemented to detect variable-length events within the arbitrary-formatted stream:
string stream = "A;030216;182748 ;00;FF;AA;01; 030216;182749;AA;02";
string[] lines = SplitLines(batch, "A", "AA", ";");
Split-rules are:
- all elements of input stream are separated by separator(, for example).
- each event is bounded by the special markers(L and I for example)
- end marker is previous element of event-sequence
static string[] SplitLines(string stream, string startSeq, string endLine, string separator) {
string[] elements = stream.Split(new string[] { separator }, StringSplitOptions.RemoveEmptyEntries);
int pos = 0;
List<string> line = new List<string>();
List<string> lines = new List<string>();
State state = State.SeqStart;
while(pos < elements.Length) {
string current = elements[pos].Trim();
switch(state) {
case State.SeqStart:
if(current == startSeq)
state = State.LineStart;
continue;
case State.LineStart:
if(++pos < elements.Length) {
line.Add(startSeq);
state = State.Line;
}
continue;
case State.Line:
if(current == endLine)
state = State.LineEnd;
else
line.Add(current);
pos++;
continue;
case State.LineEnd:
line.Add(endLine);
line.Add(current);
lines.Add(string.Join(separator, line));
line.Clear();
state = State.LineStart;
continue;
}
}
return lines.ToArray();
}
enum State { SeqStart, LineStart, Line, LineEnd };
f you want to split the string into multiple strings, you need a set of rules, which are implementable. In your case i would start splitting the complete string by the given comma , and than go though the elements in a loop. All the strings in the loop will be appended in a StringBuilder. If your ruleset say you need a new line, just add it via yourBuilder.Append('\r\n') or use AppendLine.

Confusing indexing error while going line by line through some text

I'm reading in some text, line by line, and I'd like to tokenize the words and create 1-grams and 2-grams, but I think there's a problem with my indexing because I either get an index error or it'll say that the item I'm trying to modify in my dictionary doesn't exist, which is totally weird, since I wrote the code to first make the dictionary item and if it already exists, to increment a counter.
Basically, my dictionaries are of the form (n-gram string, frequency int)
System.IO.StreamReader lines = new System.IO.StreamReader("myfile");
while (true)
{
string line = lines.ReadLine().ToLower();
if (line == null) break;
if (line.Trim().Length == 0) continue;
string[] tokens = Regex.Split(line, "[^\\w']+");
for (int i = 0; i < tokens.Count()-1; i++)
{
try
{
one_gram.Add(tokens[i], 1);
two_gram.Add(tokens[i] + " " + tokens[i + 1], 1);
}
catch
{
one_gram[tokens[i]]++;
two_gram[tokens[i] + " "+tokens[i + 1]]++;
}
}
}
Can anyone look at my code and tell me where I went wrong? The problem seems to occur at the end of the for loop at the first line, but if I do
for(int i=0;i<tokens.Count()-3;i++)
then the error happens in the second line... but I'm not sure exactly what's causing it.
EDIT: As per suggestions, I tried using the ContainsKey method, but I still get an error near the end of the first line saying that I'm adding a Key that already exists, even though the if statements are supposed to catch that?!
for (int i = 0; i < tokens.Count()-1; i++)
{
if (one_gram.ContainsKey(tokens[i]))
{
one_gram[tokens[i]]++;
}
if (two_gram.ContainsKey(tokens[i] + " " + tokens[i + 1]))
{
two_gram[tokens[i] + " " + tokens[i + 1]]++;
}
one_gram.Add(tokens[i], 1);
two_gram.Add(tokens[i] + " " + tokens[i + 1], 1);
}
You need to use an else (or break):
for (int i = 0; i < tokens.Count() - 1; i++)
{
// Save yourself typing errors by creating variables to hold
// the key values and then you can just use the variable name
var oneGramKey = tokens[i];
var twoGramKey = string.Format("{0} {1}", tokens[i], tokens[i + 1]);
if (one_gram.ContainsKey(oneGramKey))
{
one_gram[oneGramKey]++;
}
else
{
one_gram.Add(oneGramKey, 1);
}
if (two_gram.ContainsKey(twoGramKey))
{
two_gram[twoGramKey]++;
}
else
{
two_gram.Add(twoGramKey, 1);
}
}

I parse text from richTextBox how can i clear " and , from the string?

This is the code:
public static string ParseText(string text, int startPos, int endPos)
{
string images = "";
if (startPos >= 0 && endPos > startPos)
{
images = text.Substring(startPos + 1, endPos - startPos - 1);
images.Replace(',',' ');
}
return images;
}
Im using this part to clean/remove , and "
entries = images.Split(new[] { ',' });
for (var i = 0; i < entries.Length; i++)
{
entries[i] = entries[i].Replace("\"", "");
}
For example if i have this part of text:
"http://www.niederschlagsradar.de/images.aspx?jaar=-6&type=europa.cld&datum=201311221800&cultuur=en-GB&continent=europa","http://www.niederschlagsradar.de/images.aspx?jaar=-6&type=europa.cld&datum=201311222100&cultuur=en-GB&continent=europa","http://www.niederschlagsradar.de/images.aspx?jaar=-6&type=europa.cld&datum=201311230000&cultuur=en-GB&continent=europa","http://www.niederschlagsradar.de/images.aspx?jaar=-6&type=europa.cld&datum=201311230300&cultuur=en-GB&continent=europa","http://www.niederschlagsradar.de/images.aspx?jaar=-6&type=europa.cld&datum=201311230600&cultuur=en-GB&continent=europa","http://www.niederschlagsradar.de/images.aspx?jaar=-6&type=europa.cld&datum=201311230900&cultuur=en-GB&continent=europa","
And its longer...But in this example i want to remove all the " and ,
If im using the code as it is now the result is:
Im getting only the first link:
http://www.niederschlagsradar.de/images.aspx?jaar=-6&type=europa.cld&datum=201311221800&cultuur=en-GB&continent=europa
If i remove the lines:
entries = images.Split(new[] { ',' });
for (var i = 0; i < entries.Length; i++)
entries[i] = entries[i].Replace("\"", "");
Then i will see all the text but with , and "
What is wrong with cleaning the , and "?
Why it show me only the first text part and not all the rest ?
strings in C# are immutable.
images.Replace(',', '');
... by design does not affect images. What you need is:
images = images.Replace(',', ' ');
Perhaps you want them as a joined string?
var result = string.Join(Environment.NewLine, images.Split(new[] { ',' }).Select(e => e.Replace("\"", "")));
If I'm understanding your comment correctly,
// could easily be an extension method
public static string ReplacingChars(string source, char[] toReplace, string withThis)
{
return string.Join(withThis, source.Split(toReplace, StringSplitOptions.None));
}
// usage:
images = ReplacingChars(images, new [] {',', '"'}, " ");
Try using string.Replace(). See MSDN for more information.
e.g.
images.Replace(',','');
The following works for me!
string ParseText(string input)
{
// Replace quotes with nothing at all...
var noQuotes = input.Replace("\"", "");
// Replace commas with, I dunno, "whatever you want"...
// If you want to just get rid of the commas, you could use "",
// or if you want a space, " "
return input.Replace("," "whatever you want");
}

C# - Initializing an array within a loop to values in a different array

I have a array called str that is made up of a series of comma separated pairs. For example, str[0] is "Bill, John". I am attempting to loop through str and split apart each pair at the comma into arrays called First and Second. I am having difficulty achieving this, if anyone can help I would greatly appreciate it. This is my code I'm working with:
while (a < length)
{
var Pairs = str[a].Split(',');
Console.WriteLine(a + ": " + str[a]);
first[a] = Pairs[0];
second[a] = Pairs[1];
a++;
}
The problem I am having is with the first[a] and second[a] lines. I'm having trouble figuring out what data type those variables are supposed to be, it seems like I get a different error for each type I declare them as before the while loop.
Here are the errors I get on the variable implementations within the loop:
If I declare them as arrays: "Cannot apply indexing with [] to an expression of type 'System.Array'"
Array first;
Array second;
while (a < length)
{
var Pairs = str[a].Split(',');
Console.WriteLine(a + ": " + str[a]);
first[a] = Pairs[0];
second[a] = Pairs[1];
a++;
}
as ints: "Cannot apply indexing with [] to an expression of type 'int'"
int first;
int second;
while (a < length)
{
var Pairs = str[a].Split(',');
Console.WriteLine(a + ": " + str[a]);
first[a] = Pairs[0];
second[a] = Pairs[1];
a++;
}
as strings: "Property or indexer 'string.this[int]' cannot be assigned to -- it is read only"
string first;
string second;
while (a < length)
{
var Pairs = str[a].Split(',');
Console.WriteLine(a + ": " + str[a]);
first[a] = Pairs[0];
second[a] = Pairs[1];
a++;
}
as vars: "Implicitly-typed local variables must be initialized" (This error is on the declaration, not within the loop itself. If I initialize it, it is implicitly converting to one of the above data types and throwing the errors associated with them I've mentioned)
var first;
var second;
while (a < length)
{
var Pairs = str[a].Split(',');
Console.WriteLine(a + ": " + str[a]);
first[a] = Pairs[0];
second[a] = Pairs[1];
a++;
}
Based on new edit:
Ok, type Array is never used. It is internal. To use an array you need to use the bracket notation (it seems strange but this comes from C, C++, and Java.)
That looks something like this:
string [10] first;
HOWEVER, in more modern C# you can use generics. They just make more sense in the modern object oriented world. To use them you specify a type they operate on. In many ways they act like you would expect an array to work but with added features. To use them, in your example would, it look like this:
ArrayList<string> first = new ArrayList<string>();
ArrayList<string> second = new ArrayList<string>();
foreach(string a in str)
{
var Pairs = a.Split(',');
first.Add(Pairs[0]);
second.Add(Pairs[1]);
}
The easy way to do this in C# is with the foreach loop.
int index = 0;
foreach(string a in str)
{
var Pairs = a.Split(',');
first[index] = Pairs[0];
second[index] = Pairs[1];
index++;
}
However, your code could work -- except I don't see where length comes from. Maybe your code should be like this?
int a = 0;
while (a < str.Length)
{
var Pairs = str[a].Split(',');
Console.WriteLine(a + ": " + str[a]);
first[a] = Pairs[0];
second[a] = Pairs[1];
a++;
}
Try this one
string[] str = new string[1];
str[0] = "Bill,John";
string[] first = new string[1];
string[] second = new string[1];
string[] pairs = new string[1];
int a = 0;
while(a<str.Length)
{
pairs = str[a].Split(',');
first[a] = pairs[0];
second[a] = pairs[1];
Console.WriteLine(first[a] + " - " + second[a]);
a++;
}
int i = 0;
foreach (string item in str)
{
pairs = item.Split(',');
int k = pairs.Count();
first[i] = pairs[0];
second[i] = pairs[1];
Console.WriteLine(first[i] + " - " + second[i]);
i++;
}

Categories

Resources