summing splitted text from .txt file - c#

I want to summing all piece[1] in line
private async void search()
{
if (tbs.Text != null)
{
var files = await ApplicationData.Current.LocalFolder.GetFileAsync(logid.Text + ".txt");
var lines = await FileIO.ReadLinesAsync(files);
var pattern = tbs.Text;
foreach (string line in lines.Where(line => line.Contains(pattern)))
{
}
}
}
each line are something like this
income 10000
income 20000
I want to sum all the second piece (piece[1])
how to do this?

Assuming you have list like below, you can get the sum as:
List<string> list = new List<string>() { "income 10000", "income 20000", "income 30000" };
var sum = list.Sum(r => int.Parse(r.Split(' ')[1]));
The above assumes that you will have atleast 2 elements in the splitted array and its item on index 1 is of type integer. For the above you will get the result 60000
If you want to use int.TryParse then:
var sum = list.Sum(r => { int i;
return int.TryParse(r.Split(' ')[1], out i) ? i : 0; });

You can use string.Split method to do that, using the space character for separator. It will return an array of string, the amount will be the second element.
Then you convert the string value to int with int.TryParse to compute the sum.
private async void search()
{
if (tbs.Text != null)
{
var files = await ApplicationData.Current.LocalFolder.GetFileAsync(logid.Text + ".txt");
var lines = await FileIO.ReadLinesAsync(files);
var pattern = tbs.Text;
var sum = 0;
foreach (string line in lines)
{
var elements = line.Split(' ');
int value;
if (int.TryParse(elements[1], out value))
{
sum += value;
}
}
}
}

Related

Read a text file and write the texts in chunks of 1000 characters keeping the words intact in C#

I am trying to read a file and split the text after every 1000 characters. But I want to keep the words intact. So it should just split at the space. If the 1000th character is not a space, then split at the first space just before or just after it. Any idea how to do that? I am also removing the extra spaces from the text.
while ((line = file.ReadLine()) != null)
{
text = text + line.Trim();
noSpaceText = Regex.Replace(text, #"\r\n?|\n/", "");
}
List<string> rowsToInsert = new List<string>();
int splitAt = 1000;
for (int i = 0; i < noSpaceText.Length; i = i + splitAt)
{
if (noSpaceText.Length - i >= splitAt)
{
rowsToInsert.Add(noSpaceText.Substring(i, splitAt));
}
else
rowsToInsert.Add(noSpaceText.Substring(i,
((noSpaceText.Length - i))));
}
foreach(var item in rowsToInsert)
{
Console.WriteLine(item);
}
Okay, just typed this non tested solution which should do the trick:
public static List<string> SplitOn(this string input, int charLength, char[] seperator)
{
List<string> splits = new List<string>();
var tokens = input.Split(seperator);
// -1 because first token adds 1 to length
int totalLength = -1;
List<string> segments = new List<string>;
foreach(var t in tokens)
{
if(totalLength + t.Length+1 > charLength)
{
splits.Add(String.Join(" ", segments));
totalLength = -1;
segments.Clear();
}
totalLength += t.Length + 1;
segments.Add(t);
}
if(segments.Count>0)
{
splits.Add(String.Join(" ", segments));
}
return splits;
}
It's an extension Method, which splits an input text in segments by whitespaces, means, i iterate over an array with just words. Then counting the length of each segment, checking for totallength and add it to result list.
An alternate solution:
public static List<string> SplitString(string stringInput, int blockLength)
{
var output = new List<string>();
var count = 0;
while(count < stringInput.Length)
{
string block = "";
if(count + blockLength > stringInput.Length)
{
block = stringInput.Substring(count, stringInput.Length - count);
}
else
{
block = stringInput.Substring(count, blockLength + 1);
}
if(block.Length < blockLength)
{
output.Add(block);
count += block.Length;
}
else if(block.EndsWith(" "))
{
output.Add(block);
count = count+blockLength + 1;
}
else
{
output.Add(block.Substring(0, block.LastIndexOf(" ")));
count = count + block.LastIndexOf(" ") +1;
}
}
return output;
}

Increment string if exists

I need a piece of code that increments end of string in "[]" brackets, but I got headache with that.
Thing is, if name "test" exists in given collection, algorithm should return test_[0], if both exists then "test_[1]" etc. That works so far. But when I tried to pass as currentName value "test_[something]" algorithm creates something like test_[0]_[0], test_[0]_[1] instead of test_[somenthing+someNumber]. Does anyone know the way to change this behavior?
// test test, test_[2], test_[3]
protected string GetDistinctName2(string currentName, IEnumerable<string> existingNames)
{
int iteration = 0;
if (existingNames.Any(n => n.Equals(currentName)))
{
do
{
if (!currentName.EndsWith($"({iteration})"))
{
currentName = $"{currentName}_[{++iteration}]";
}
}
while (existingNames.Any(n => n.Equals(currentName)));
}
return currentName;
}
EDIT :
The best solution so far is that(I can bet that I've seen it here, but someone had to delete)
public static void Main()
{
var currentOriginal = "test";
var existingNamesOriginal = new[] { "test", "test_[2]", "test_[3]" };
string outputOriginal = GetDistinctNameFromSO(currentOriginal, existingNamesOriginal);
Console.WriteLine("original : " + outputOriginal);
Console.ReadLine();
}
protected static string GetDistinctNameFromSO(string currentName,
IEnumerable<string> existingNames)
{
if (null == currentName)
throw new ArgumentNullException(nameof(currentName));
else if (null == existingNames)
throw new ArgumentNullException(nameof(existingNames));
string pattern = $#"^{Regex.Escape(currentName)}(?:_\[(?<Number>[0-9]+)\])?$";
Regex regex = new Regex(pattern);
var next = existingNames
.Select(item => regex.Match(item))
.Where(match => match.Success)
.Select(match => string.IsNullOrEmpty(match.Groups["Number"].Value)
? 1
: int.Parse(match.Groups["Number"].Value))
.DefaultIfEmpty()
.Max() + 1;
if (next == 1)
return currentName; // No existingNames - return currentName
else
return $"{currentName}_[{next}]";
}
For given "test" string it returns "test_[4]" which is excellent, but if given string is let's say "test_[2]" it should also return "test_[4]"(string with given pattern with first free number), but it returns "test_[2]_[2]" instead.
I will try answer with minimal adjustments to your code:
Use square brackets to check if name exists
Use a local variable to prevent adding [0] over and over
increment iteration on every do/while loop
if the result, should never be "test", exclude it from the existing results
The result looks like (not tested, but this should get you on your way):
// test test, test_[2], test_[3]
protected string GetDistinctName2(string currentName, IEnumerable<string> existingNames)
{
int iteration = 0;
// Use a different variable this will prevent you from adding [0] again and again
var result = currentName;
if (existingNames.Where(s => s != currentName).Any(n => n.Equals(result)))
{
do
{
// Use square brackets
if (!result .EndsWith($"[{iteration}]"))
{
result = $"{currentName}_[{iteration}]";
}
iteration++; // Increment with every step
}
while (existingNames.Any(n => n.Equals(result)));
}
return result;
}
Here's a simpler rewrite:
protected string GetDistinctName2(string currentName, IEnumerable<string> existingNames)
{
int iteration = 0;
var name = currentName;
while(existingNames.Contains(name))
{
name = currentName + "_[" + (iteration++) + "]";
}
return name;
}
Tests:
GetDistinctName2("test", new List<string> {"test", "test_[0]", "test_[2]", "test_[3]"}).Dump();//Out: test_[1]
GetDistinctName2("test", new List<string> {"test", "test_[0]", "test_[1]", "test_[2]", "test_[3]"}).Dump();//Out: test_[4]
GetDistinctName2("test", new List<string> {}).Dump();//Out: test
Your description of your problem and your code and completely different. Here will increment a number inside the square brackets without appending additional text.
The change from the initial code addresses a problem mentioned in the question about including text inside the square brackets with a number. Below you can replace something with other text.
protected string GetDistinctName2(string currentName, IEnumerable<string> existingNames)
{
int iteration = 0;
string nextName = currentName;
while (existingNames.Contains(nextName))
{
nextName = $"{currentName}_[something{iteration}]";
iteration++;
}
return nextName;
}
C# interactive shell example:
> GetDistinctName2("test", new List<string>() { "test", "test_[something0]", "test_[something1]"})
"test_[something2]"

Extract index numbers from list of string

I have a list of strings where those strings have an index in each string and I need to extract the index from that string and put it in a List<int>.
Here's is a list example:
List<string> values = new List<string>();
values.Add("cohabitantGender");
values.Add("additionalDriver0LastName");
values.Add("additionalDriver0AgeWhenLicensed");
values.Add("vehicle0City");
values.Add("vehicle1City");
values.Add("vehicle2City");
values.Add("vehicle3City");
from this list I need to extract the indexes from the values vehicleXCity.
I have this code right now:
public static List<int> FormObjectIndexExtractor(List<string> values, string prefix, string suffix)
{
var selectedMatches = values.Where(v => v.StartsWith(prefix) && v.EndsWith(suffix)).Select(v=> v).ToList();
var indexes = new List<int>();
foreach (var v in selectedMatches) indexes.Add(int.Parse(Regex.Match(v, #"\d+").Value));
return indexes;
}
And I'm using it like this:
List<int> indexes = FormObjectIndexExtractor(values, "vehicle", "City");
But if I have a value like vehicle4AnotherCity the code will work in the wrong way.
Does anyone have some alternative to this code that may help?
Below is an extension helper class incase you have a more robust list and you require multiple exclusion options
public class INumberList : List<string>
{
public List<int> GetNumberList()
{
List<int> numberList = new List<int>();
for (int i = 0; i < this.Count; i++)
{
numberList.Add(GetIntFromString(this[i]));
}
return numberList;
}
public INumberList ExcludeIndex(string prefix, string suffix)
{
for (int i = 0; i < this.Count; i++)
{
if (this[i].StartsWith(prefix) && this[i].EndsWith(suffix))
{
//remove non needed indexes
this.RemoveAt(i);
}
}
return this;
}
public static int GetIntFromString(String input)
{
// Replace everything that is no a digit.
String inputCleaned = Regex.Replace(input, "[^0-9]", "");
int value = 0;
// Tries to parse the int, returns false on failure.
if (int.TryParse(inputCleaned, out value))
{
// The result from parsing can be safely returned.
return value;
}
return 0; // Or any other default value.
}
}
Then use like this:
INumberList values = new INumberList();
values.Add("cohabitantGender");
values.Add("additionalDriver0LastName");
values.Add("additionalDriver0AgeWhenLicensed");
values.Add("vehicle0City");
values.Add("vehicle1City");
values.Add("vehicle2City");
values.Add("vehicle3City");
//Get filtered index list with multiple exclusion option
List<int> indexList = values.ExcludeIndex("cohabitantGender","")
.ExcludeIndex("additionalDriver","AgeWhenLicensed")
.GetNumberList();
//will return [0,0,1,2,3]
Try this:
public static List<int> FormObjectIndexExtractor(List<string> values, string prefix, string suffix)
{
var s = "^" + prefix + #"(\d+)\.*?" + suffix + "$";
return values
.Where(v => Regex.Match(v, s).Success)
.Select(v=> int.Parse(Regex.Match(v, s).Groups[1].Value))
.ToList();
}
Here is a solution (using modern C# features) that does not use Regex:
public static List<int> FormObjectIndexExtractor(IEnumerable<string> values, string prefix, string suffix)
{
int? TryParseItem(string val)
{
if (val.Length <= prefix.Length + suffix.Length || !val.StartsWith(prefix) || !val.EndsWith(suffix))
return null;
var subStr = val.Substring(prefix.Length, val.Length - prefix.Length - suffix.Length);
if (int.TryParse(subStr, out var number))
return number;
return null;
}
return values.Select(TryParseItem).Where(v => v.HasValue).Select(v => v.Value).ToList();
}
This version splits all the parts of string.
public static List<int> FormObjectIndexExtractor(List<string> values, string prefix, string suffix)
{
List<int> ret = new List<int>();
Regex r = new Regex("^([a-zA-Z]+)(\\d+)([a-zA-Z]+)$");
foreach (var s in values)
{
var match = r.Match(s);
if (match.Success)
{
if (match.Groups[1].ToString() == prefix && match.Groups[3].ToString() == suffix)
{
ret.Add(int.Parse(match.Groups[2].ToString()));
}
}
}
return ret;
}
or alternatively:
public static List<int> FormObjectIndexExtractor(List<string> values, string prefix, string suffix)
{
List<int> ret = new List<int>();
Regex r = new Regex($"^{prefix}(\d+){suffix}$");
foreach (var s in values)
{
var match = r.Match(s);
if (match.Success)
{
ret.Add(int.Parse(match.Groups[1].ToString()));
}
}
return ret;
}
This is the more generic version.
Regex match:
starts with 'vehicle'
matches a number
ends with 'city'.
Parse and return as List<int>
var indexes = values.Where(a => Regex.IsMatch(a, #"^vehicle\d+City$")).
Select(k => int.Parse(Regex.Match(k, #"\d+").Value)).ToList();

C# Add a blank value in between string in of CSV file

I have this on a string that is generated from a list how can I add a blank value in between the string.
using (var file = File.CreateText()
{
foreach (var permutation in result)
{
file.WriteLine(string.Join(",", permutation));
//i++;
}
}
Here is the result:
string result = A,B,C,D,E,F,G,H,I,J
How can I add a blank value ", ," in the result at a specific index
Example: A,B,C,D,E,F, ,G,H,I,J
Note: result is a permutation and length is not consistent
Result is a IEnumerable can it be split?
You can split your string with the comma as the separator, go through your characters and add them to a list. Add an extra empty string at your desired index and join the data back together. This way you don't have to deal with deciding if you need to add a commar or not when concatenating the strings.
var index = 6;
var data = "A,B,C,D,E,F,G,H,I,J";
var chars = data.Split(new [] { ',' });
List<string> resultData = new List<string>();
var i = 0;
foreach (var c in chars) {
if (i == index) {
resultData.Add(" ");
}
i++;
resultData.Add(c);
}
var result = string.Join(",", resultData.ToArray();
You can use the following basic algorithm to follow your questions code logic:
using (var file = File.CreateText())
{
int i = -1;// Loop counter
int termReplacementIndex = 3;// Input or constant to find letter to replace
foreach (var permutation in result)
{
i++;
if (i == ((termReplacementIndex * 2) - 2))// Only stops on letters not commas
{
file.WriteLine(string.Join(",", " ,"));// Adding of blank " "
}
file.WriteLine(string.Join(",", permutation));// Adding of letter
}
}
If permutation is a list you can just insert a null value at the required index:
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var list = new List<string>();
list.Add("test 1");
list.Add("test 2");
list.Add("test 3");
list.Insert(2, null);
var str = string.Join(",", list);
Console.WriteLine(str); // test 1,test 2,,test 3
}
}
Modify the Collection before joining it so you wont have to split it and iterate it again.
As the side of permutation vary you could be trying to insert at index X when X is larger greater permutation.Count() instead of an ArgumentOutOfRangeException I decide to add the element at the end. But you will have to define that.
public string CsvProjection(List<string> inputs, int needleIndex, string needleValue)
{
if (needleIndex < 0)
{
throw new ArgumentOutOfRangeException("needleIndex must be positive.");
}
if (needleIndex > inputs.Count())
{//Either throw an exception because out of bound or add to the end
inputs.Add(needleValue);
}
inputs.Insert(needleIndex, needleValue);
return string.Join(",", inputs);
}
Usage simply add the value and the index variable:
var needleIndex= 2;
var needleValue = "My New Value";
using (var file = File.CreateText()
{
foreach (var permutation in result)
{
file.WriteLine(CsvProjection(permutation, needleIndex, needleValue));
}
}

How do I produce a full set of combinations with string manipulation?

I have a small project where I have an input sentence where it is possible for the user to specify variations:
The {small|big} car is {red|blue}
Above is a sample sentence i want to split into 4 sentences, like this:
The small car is red
The big car is red
The small car is blue
The big car is blue
I can't seem to wrap my mind around the problem. Maybe someone can helt me pls.
Edit
Here is my initial code
Regex regex = new Regex("{(.*?)}", RegexOptions.Singleline);
MatchCollection collection = regex.Matches(richTextBox1.Text);
string data = richTextBox1.Text;
//build amount of variations
foreach (Match match in collection)
{
string[] alternatives = match.Value.Split(new char[] { '|', '{', '}' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string alternative in alternatives)
{
//here i get problems
}
}
It sounds like you need a dynamic cartesian function for this. Eric Lippert's blog post written in response to Generating all Possible Combinations.
Firstly, we need to parse the input string:
Regex ex = new Regex(#"(?<=\{)(?<words>\w+(\|\w+)*)(?=\})");
var sentence = "The {small|big} car is {red|blue}";
then the input string should be modified to be used in string.Format-like functions:
int matchCount = 0;
var pattern = ex.Replace(sentence, me =>
{
return (matchCount++).ToString();
});
// pattern now contains "The {0} car is {1}"
then we need to find all the matches and to apply Eric's excellent CartesianProduct extension method:
var set = ex.Matches(sentence)
.Cast<Match>()
.Select(m =>
m.Groups["words"].Value
.Split('|')
).CartesianProduct();
foreach (var item in set)
{
Console.WriteLine(pattern, item.ToArray());
}
this will produce:
The small car is red
The small car is blue
The big car is red
The big car is blue
and, finally, the CartesianProduct method (taken from here):
static IEnumerable<IEnumerable<T>> CartesianProduct<T>(
this IEnumerable<IEnumerable<T>> sequences)
{
IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
return sequences.Aggregate(
emptyProduct,
(accumulator, sequence) =>
from accseq in accumulator
from item in sequence
select accseq.Concat(new[] {item}));
}
private void ExpandString( List<string> result, string text )
{
var start = text.IndexOf('{');
var end = text.IndexOf('}');
if (start >= 0 && end > start)
{
var head = text.Substring(0, start);
var list = text.Substring(start + 1, end - start - 1).Split('|');
var tail = text.Substring(end + 1);
foreach (var item in list)
ExpandString(result, head + item + tail);
}
else
result.Add(text);
}
Use like:
var result = new List<string>();
ExpandString(result, "The {small|big} car is {red|blue}");
If you don't know the number of variations, recursion is your friend:
static public IEnumerable<string> permute(string template)
{
List<string> options;
string before;
string after;
if (FindFirstOptionList(template, out options, out before, out after))
{
foreach (string option in options)
{
foreach (string permutation in permute(before + option + after))
{
yield return permutation;
}
}
}
else
{
yield return template;
}
}
static public bool FindFirstOptionList(string template, out List<string> options, out string before, out string after)
{
before = string.Empty;
after = string.Empty;
options = new List<string>(0);
if (template.IndexOf('{') == -1)
{
return false;
}
before = template.Substring(0, template.IndexOf('{'));
template = template.Substring(template.IndexOf('{') + 1);
if (template.IndexOf('}') == -1)
{
return false;
}
after = template.Substring(template.IndexOf('}') + 1);
options = template.Substring(0, template.IndexOf('}')).Split('|').ToList();
return true;
}
use is similar to danbystrom's solution, except this one returns an IEnumerable instead of manipulating one of the calling parameters. Beware syntax errors, etc
static void main()
{
foreach(string permutation in permute("The {small|big} car is {red|blue}"))
{
Console.WriteLine(permutation);
}
}
I would propose to split the input text into an ordered list of static and dynamic parts. Each dynamic part itself contains a list that stores its values and an index that represents the currently selected value. This index is intially set to zero.
To print out all possible combinations you at first have to implement a method that prints the complete list using the currently set indices of the dynamic parts. For the first call all indices will be set to zero.
Now you can increment the index of the first dynamic part and print the complete list. This will give you the first variation. Repeat this until you printed all possible values of the remaining dynamic parts.
Consider nesting iterative loops. Something like...
foreach(string s in someStringSet)
{
foreach(string t in someOtherStringSet)
{
// do something with s and t
}
}
Perhaps you are looking for this:
Edited version
static void Main(string[] args)
{
var thisstring = "The {Small|Big} car is {Red|Blue}";
string FirstString = thisstring.Substring(thisstring.IndexOf("{"), (thisstring.IndexOf("}") - thisstring.IndexOf("{")) + 1);
string[] FirstPossibility = FirstString.Replace("{", "").Replace("}", "").Split('|');
thisstring = thisstring.Replace(FirstString, "[0]");
string SecondString = thisstring.Substring(thisstring.IndexOf("{"), (thisstring.IndexOf("}") - thisstring.IndexOf("{")) + 1);
string[] SecondPosibility = SecondString.Replace("{", "").Replace("}", "").Split('|');
thisstring = thisstring.Replace(SecondString, "{1}").Replace("[0]", "{0}");
foreach (string tempFirst in FirstPossibility)
{
foreach (string tempSecond in SecondPosibility)
{
Console.WriteLine(string.Format(thisstring, tempFirst, tempSecond));
}
}
Console.Read();
}
Something like this should work:
private void Do()
{
string str = "The {small|big} car is {red|blue}";
Regex regex = new Regex("{(.*?)}", RegexOptions.Singleline);
int i = 0;
var strWithPlaceHolders = regex.Replace(str, m => "{" + (i++).ToString() + "}");
var collection = regex.Matches(str);
var alternatives = collection.OfType<Match>().Select(m => m.Value.Split(new char[] { '|', '{', '}' }, StringSplitOptions.RemoveEmptyEntries));
var replacers = GetReplacers(alternatives);
var combinations = new List<string>();
foreach (var replacer in replacers)
{
combinations.Add(string.Format(strWithPlaceHolders, replacer));
}
}
private IEnumerable<object[]> GetReplacers(IEnumerable<string[]> alternatives)
{
return GetAllPossibilities(0, alternatives.ToList());
}
private IEnumerable<object[]> GetAllPossibilities(int level, List<string[]> list)
{
if (level == list.Count - 1)
{
foreach (var elem in list[level])
yield return new[] { elem };
}
else
{
foreach (var elem in list[level])
{
var thisElemAsArray = new object[] { elem };
foreach (var subPossibilities in GetAllPossibilities(level + 1, list))
yield return thisElemAsArray.Concat(subPossibilities).ToArray();
}
}
yield break;
}
string color = SomeMethodToGetColor();
string size = SomeMethodToGetSize();
string sentence = string.Format("The {0} car is {1}", size, color);

Categories

Resources