C# merge lines of strings into groups of 3 at a time - c#

I have a string like this (including newlines)
A2,
10.22,
-57,
A,
10.23,
-68,
A2,
10.24,
-60,
LB,
10.25,
-62,
I am trying to make this string to look like this:
A2,10.22,-57,
A,10.23,-68,
A2,10.24,-60,
LB,10.25,-62,
I need to join string in every 3 line i have tried :
int numLines = a.Split('\n').Length;
for (int i = 0; i < numLines; i += 3)
{
richTextBox1.Text = a.Replace("\n", "");
}
But it is not working for me. Please help me out

You can also approach this with LINQ, by using the index overload of .Select to retain a running count of the line numbers, and then to group them into groups of 3 - I've used integer division to Floor the line index, 3 at a time, but there are likely other suitable ways.
var groups = values.Select((s, idx) => (Index: idx / 3, Value: s))
.GroupBy(x => x.Index);
Where each item in the groups above will be IEnumerable<(Index, Value)>.
You'll also need to be wary of newlines - these may be \r\n in Windows, not just the \n you've indicated.
Here's an example:
var a =
#"A2,
10.22,
-57,
A,
10.23,
-68,
A2,
10.24,
-60,
LB,
10.25,
-62,";
var values = a.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
var groups = values.Select((s, idx) => (Index: idx / 3, Value: s))
.GroupBy(x => x.Index);
foreach (var grp in groups)
{
Console.WriteLine(string.Join("", grp.Select(x => x.Value)));
}
Since you've already got commas at the end of each string (including the last one), there's no need to add another separator.
Output:
A2,10.22,-57,
A,10.23,-68,
A2,10.24,-60,
LB,10.25,-62,

Why not use the array that the split gives you instead?
var newArr = a.Split('\n');
for (int i = 0; i < newArr.Length; i += 3)
{
richTextBox1.Text = newArr[i] + newArr[i + 1] + newArr[i + 2];
}
Just don't forget to check the length of the arrays so that you don't get a IndexOutOfRange Exception.

I'm assuming that the input is actually coming from a file here.
var file = //file path
var sb = new StringBuilder();
var lineNum = 1;
var output = string.Empty;
using (var reader = new StreamReader(file))
{
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
if (lineNum % 3 == 0)
{
output += sb.ToString() + "\n";
sb.Clear();
}
else
sb.Append(line);
lineNum++;
}
}
richTextBox1.Text = output;

Try this solution which is a combination of linq and for loop
var result = "";
var items = yourInputString.Split('\n');
for(var i=0; i<items.Count();i=i+3)
{
result += string.Join(",",items.Skip(i).Take(3))+"\n";
}

static void Main(string[] args)
{
var Lines = System.IO.File.ReadAllLines("input.txt");
var Result = new StringBuilder();
var SB = new StringBuilder();
for (var i = 0; i < Lines.Length; i++)
{
SB.Append(Lines[i]);
if ((i+1) % 3 == 0)
{
Result.Append($"{SB.ToString()}{Environment.NewLine}");
SB.Clear();
}
}
System.IO.File.WriteAllText("output.txt", Result.ToString());
}

Try to use Aggregate function
var outPutList = data.Replace("\r", string.Empty).Replace("\n", string.Empty).Split(",").Aggregate(new StringBuilder(""), (x, y) =>
{
if (double.TryParse(y, out double parsedValue))
x.Append(" " + parsedValue);
else
{
x.Append(Environment.NewLine);
x.Append(y.Trim());
}
return x;
});
richTextBox1.Text = outPutList.ToString();
Here is the output

try this works
private void button1_Click(object sender, EventArgs e)
{
//put your string in a textxbox with multiline property set to true
string[] s = textBox1.Text.Replace("\r", "").Replace("\n", "").Split(',');
string r = "";
for (int i = 0; i < s.Length; i++)
{
r = r + s[i] + ",";
if ((i + 1) % 3 == 0)
r = r + "+";
}
if (r.Substring(r.Length - 1, 1) == ",")
r = r.Substring(0, r.Length - 1);
if (r.Substring(r.Length - 1, 1) == "+")
r = r.Substring(0, r.Length - 1);
string[] finalArrayString = r.Trim().Split('+');
//just for show the result
textBox1.Text = "";
for (int i = 0; i < finalArrayString.Length; i++)
textBox1.Text = textBox1.Text + finalArrayString[i] + "\r\n";
}
hope it helps you

Related

How to rearrange a string so no adjent letters are the same

I am trying to rearrange a given string, so no two adjacent letters are the same.
For that I'm thinking to count every distinct letter's occurence, and then rearrange the string the characters occurence number
example:
Input: AABAABBC
Output: AAAABBBC
and after that spliting it in 2 different strings
AAAA BBBC
and then trying to get the final result.
My question is how do I rearrange the string without using Linq?
Here is my code so far:
private static string GetDistinctChars(string text)
{
string result = "";
foreach (char c in text)
{
if (!result.Contains(c))
{
result += c;
}
}
return result;
}
private static double GetCharOccurrence(string text, char charToCount)
{
int count = 0;
foreach (char c in text)
{
if (c == charToCount)
{
count++;
}
}
return count;
}
You can do it like that:
string example = "AABBAACDCAA";
var orderList = example.OrderBy(x => x).ToList();
List<string> letters = new List<string>();
string temp = string.Empty;
for(int i = 0; i < orderList.Count; i++)
{
temp += orderList[i];
if (i + 1 == orderList.Count)
{
letters.Add(temp);
break;
}
if(orderList[i] != orderList[i + 1])
{
letters.Add(temp);
temp = string.Empty;
}
}
string result = String.Join(" ", letters);
Console.WriteLine(result);
If you don't want to use Linq Order by method, you should implement sorting algorithm like this:
static char[] SortArray(char[] array)
{
int length = array.Length;
char temp = array[0];
for (int i = 0; i < length; i++)
{
for (int j = i + 1; j < length; j++)
{
if (array[i] > array[j])
{
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
return array;
}
and use it in your program:
string example = "AABBAACDCAA";
var orderList = SortArray(example.ToCharArray());
List<string> letters = new List<string>();
string temp = string.Empty;
for(int i = 0; i < orderList.Length; i++)
{
temp += orderList[i];
if (i + 1 == orderList.Length)
{
letters.Add(temp);
break;
}
if(orderList[i] != orderList[i + 1])
{
letters.Add(temp);
temp = string.Empty;
}
}
string result = String.Join(" ", letters);
Console.WriteLine(result);
alternativly, if you don't want to use list anymore, you can operate only on strigns:
string example = "AABBAACDCAA";
var orderList = SortArray(example.ToCharArray());
string lettersString = string.Empty;
for (int i = 0; i < orderList.Length; i++)
{
lettersString += orderList[i];
if (i + 1 == orderList.Length)
break;
if (orderList[i] != orderList[i + 1])
lettersString += " ";
}
Console.WriteLine(lettersString);
You can find your problem on LeetCode, it's a problem #767.
My algorithm is
If we have too many of same characters, we can't solve the problem (e.g. "aaaaaabc")
If solution exists, we can sort characters aababc -> aaabbc and then take item by item from the beginning and from the center:
For instance:
aababc -> aaabbc (ordered by frequency: a appears 3 time, b - 2, c - 1)
then
aaabbc => ab
^ ^
take these
aaabbc => abab
^ ^
take these
aaabbc => ababac <- final answer
^ ^
take these
Code:
using System.Linq;
using System.Text;
...
public static string ReorganizeString(string s) {
int count = s.GroupBy(c => c).Max(g => g.Count());
// One of the item is too frequent, no solutions
if (count > (s.Length + 1) / 2)
return "";
string st = string.Concat(s
.GroupBy(c => c)
.OrderByDescending(g => g.Count())
.ThenBy(g => g.Key) // not required, just for aesthetic
.SelectMany(c => c));
StringBuilder sb = new StringBuilder(s.Length);
for (int i = 0; i < s.Length / 2; ++i) {
sb.Append(st[i]);
sb.Append(st[(st.Length + 1) / 2 + i]);
}
// Middle character
if (s.Length % 2 != 0)
sb.Append(st[st.Length / 2]);
return sb.ToString();
}
Demo:
string value = "AABAABBC";
Console.Write(ReorganizeString(value));
Output:
ABABABAC
Fiddle it yourself.
Edit: If StringBuilder (as well as System.Text) is really forbidden, we can use string, which, however, slows down the routine:
using System.Linq;
...
public static string ReorganizeString(string s) {
int count = s.GroupBy(c => c).Max(g => g.Count());
// One of the item is too frequent, no solutions
if (count > (s.Length + 1) / 2)
return "";
string st = string.Concat(s
.GroupBy(c => c)
.OrderByDescending(g => g.Count())
.ThenBy(g => g.Key) // not required, just for aesthetic
.SelectMany(c => c));
string result = "";
for (int i = 0; i < s.Length / 2; ++i) {
result += st[i];
result += st[(st.Length + 1) / 2 + i];
}
// Middle character
if (s.Length % 2 != 0)
result += st[st.Length / 2];
return result;
}

Split and append a string?

Right now I take in a string like this "112233 112233 112233 112233", and I split it into an array like this:
string text = ProcessString("112233 112233");
string[] dates = text.Split(' ');
And that works great, but I want to use string builder to build my string so they would end up like 11-22-33 11-22-33 etc.
So I did try this:
static string ProcessString(string input)
{
StringBuilder buffer = new StringBuilder(input.Length * 3 / 2);
for (int i = 0; i < input.Length; i++)
{
if ((i > 0) & (i % 2 == 0))
buffer.Append("-");
buffer.Append(input[i]);
}
return buffer.ToString();
}
It works, but it does not match the expected output of:
11-22-33
11-22-33
My current output is:
11-22-33-
1-12-23-3
-11-22-33
What can I do to fix this?
You can process a single string simply by iterating and collecting size-2 substrings of the string, and then joining them by the - character:
string s = "112233";
List<string> parts = new List<string>(s.Length / 2);
for (int i = 0; i < s.Length; i += 2)
parts.Add(s.Substring(i, 2));
Console.WriteLine(string.Join("-", parts)); // 11-22-33
So, for your full problem, you could do this:
static string ProcessString(string input)
{
var segments = input.Split(' ').Select(s =>
{
List<string> parts = new List<string>(s.Length / 2);
for (int i = 0; i < s.Length; i += 2)
parts.Add(s.Substring(i, 2));
return string.Join("-", parts);
});
return string.Join(" ", segments);
}
How about regex:
string s = "112233";
string pattern = #"\d{2}\B";
string result = Regex.Replace(s, pattern, m => m.Value + "-");
Can i offer you another Regex + LINQ approach?
var newDates = dates.Select(d => Regex.Replace(d, ".{2}", "$0-").Trim('-'));
string result = string.Join(" ", newDates);
But i like this extension more because it's readable and re-usable:
public static IEnumerable<String> SplitInParts(this String s, Int32 partLength)
{
if (s == null)
throw new ArgumentNullException("s");
if (partLength <= 0)
throw new ArgumentException("Part length has to be positive.", "partLength");
for (var i = 0; i < s.Length; i += partLength)
yield return s.Substring(i, Math.Min(partLength, s.Length - i));
}
Then the code is even easier:
var newDates = dates.Select(d => string.Join("-", d.SplitInParts(2)));
string result = string.Join(" ", newDates);
I have this approach :
string input = "112233 445566 778899 101010";
string[] dates = input.Split(' ');
foreach (string date in dates){
Console.WriteLine(date);
string result = date.Substring(0, 2) + '-' + date.Substring(2, 2) + "-" + date.Substring(4, 2);
Console.WriteLine(result);
}
You can use Array.ConvertAll:
string str = "112233 112233 112233 112233";
string[] dates = str.Split();
dates = Array.ConvertAll(dates, s => s.Insert(4, "-").Insert(2, "-"));
foreach (var s in dates)
Console.WriteLine(s);

How do you use different separators in string.join in C#

Im trying to write a simple code that takes a string array and joins it with 2 different separator that alternates. What i'm looking for is if i have and array:
string[] myArray = new string[] {"apples","five","bananas","six","cherries","seven"};
I want to get a string like:
apples=five,bananas=six,cherries=seven
It doesn't have to use just one method but the array length may vary.
Thank you.
int i = 0;
var result = String.Join(",",myArray.GroupBy(x=>i++/2).Select(g=>String.Join("=",g)));
Write your own version:
string Merge(string sep1, string sep2, params string[] items)
{
string result = "";
for(int i = 0; i < items.Length - 1; i++)
{
result += items[i] + (i % 2 == 0 ? sep1 : sep2);
}
//add the last item
result += items[items.Length - 1];
return result;
}
Which you can use like this:
string result = Merge("=", ",", myArray);
You can use this function:
string GetJoinString(string[] data) {
var ret = new StringBuilder();
for (var i = 0; i < data.Count; i++) {
var separator = i % 2 == 0 ? '=' : ',';
ret.Append(data[i] + separator);
}
return ret.ToString();
}
var myArray = new string[] { "apples", "five", "bananas", "six", "cherries", "seven" };
var result = "";
for (var index = 0; index < myArray.Length; index = index + 2)
{
result += string.Format("{0}={1}{2}", myArray[index], myArray[index + 1],
index < myArray.Length - 2 ? "," : "");
}
return result;
You can try to use e.g.
var res = myArray.Aggregate((current, next) => current + (Array.IndexOf(myArray, next) % 2 == 0 ? ",": "=") + next);
or without search in the array it can be
int index = 0;
var res = myArray.Aggregate((current, next) => current + (index++ % 2 == 0 ? "=": ",") + next);

project euler 22 using c#

I am solving the same problem as here Project Euler #22 Python, 2205 points missing?, but I am using C#. I can't find the mistake. Here is my code:
class Program
{
static List<string> pole;
static string SaveName(StreamReader reader)
{
int znak = reader.Read();
string jmeno = "";
while ((znak < 'A') || (znak > 'Z'))
{
znak = reader.Read();
}
while (znak != ',')
{
jmeno = jmeno + (char) znak;
znak = reader.Read();
if (znak == 34) break;
}
return jmeno;
}
static void SaveNamesIntoList()
{
StreamReader reader = new StreamReader(#"../../../names.txt");
while (reader.Read() != ';')
{
pole.Add(SaveName(reader));
}
}
static void Main(string[] args)
{
pole = new List<string>();
SaveNamesIntoList();
pole.Sort();
int sum = 0;
int sum_word = 0;
string name = "";
for (int i = 0; i < pole.Count; i++)
{
name = pole[i];
sum_word = 0;
for (int u = 0; u < name.Length; u++)
{
sum_word += (name[u] - 'A' + 1);
}
sum += (sum_word * (i+1));
}
Console.WriteLine(sum);
}
}
Thanks for any answer:)
Ther reason why you have different result is than Czech language has specific letter 'CH' whitch is after 'H' so in alfabetical order without using right culture you can have sometring like this
aaa
bbb
ccc
czz
ddd
cha
There are a few issues here. You don't check if the reader reached the end of stream - you have to check if the Read returned -1. If it did - it's the end of the file. On top of that, you don't dispose the reader...
Then, as Cedric noted in the comments, you haven't really sorted the list, hence the result is wrong even after changing it to:
using (var reader = new StreamReader("names.txt"))
{
while (reader.Read() != -1)
{
pole.Add(SaveName(reader));
}
}
What you need to do is add this line (which is a bit wasteful in general, but I'll get to that in a sec):
pole = pole.OrderBy(x => x).ToList(); //<<----- this one
for (int i = 0; i < pole.Count; i++)
{
name = pole[i];
sum_word = 0;
for (int u = 0; u < name.Length; u++)
{
sum_word += (name[u] - 'A' + 1);
}
sum2 += (sum_word*(i + 1));
}
And the result is 871198282, which should be correct - at least that's what the people are saying in the linked question.
Even then, might I suggest an easier way of solving that whole problem:
var scores = Enumerable.Range('A', 'Z' - 'A' + 1)
.Select((i, ch) => new { Character = (char) i, Weight = ch + 1 })
.ToDictionary(key => key.Character, val => val.Weight);
var sum = File.ReadAllText("names.txt")
.Split(',')
.Select(x => x.Trim('"'))
.OrderBy(x => x)
.Select((x, i) => (i + 1)*x.Select(y => scores[y]).Sum())
.Sum();
Here's a version using Linq.
void Main()
{
var file = #"C:\...location.of.file...\p022_names.txt";
using (var reader = new StreamReader(file, Encoding.UTF8))
{
NameScore(reader.ReadToEnd().Replace("\"",string.Empty).Split(new[]{','})).Dump();
}
}
private long NameScore(string[] names)
{
return names.OrderBy(o => o)
.Select((l, i) => { return l.ToUpper().ToCharArray().Sum(s => (int)s - 64) * (i + 1);})
.Sum(s => s);
}

Break on space, textbox (specific condition)

I need to break on closest space to 30th character of texbox, and I got very good answer for that:
var x = 30;
if (textBox1.Text.Length > x)
{
var index = textBox1.Text.Select((c, i) => new {c, i}).TakeWhile(q => q.i < x).Where(q => q.c == ' ' ).Select(q => q.i).Last();
textBox1.Text = textBox1.Text.Insert(index, Environment.NewLine);
}
Only problem is that I need to exclude from counting characters like "#A", "#B", because they are used for text formatting.
Although perhaps not the cleanest solution. If you simply count on # (or perform a regex to detect patterns) and add that number to x (30) like:
int paramCount = test.Where(c => c == '#').Count();
var index = test.Select((c, i) => new { c, i })
.TakeWhile(q => q.i < x + paramCount)
.Where(q => q.c == ' ')
.Select(q => q.i)
.Last();
edit
In order to make sure your count only counts the first 30 characters (excluding '#'), you can perform an aggregate in advance:
int paramCount = test.Select((c, i) => new { c, i })
.Aggregate(0, (count, s) => s.c == '#' && s.i < x + count ? count + 1 : count);
textBox1.Text.Replace("#A", "").Replace("#B", "")...
You can try the code below.
string sTemp = textBox1.Text.Substring(0, 30);
sTemp = sTemp.Replace(" #A ", "");
sTemp = sTemp.Replace("#A ", "");
sTemp = sTemp.Replace(" #A", "");
sTemp = sTemp.Replace("#A", "");
sTemp = sTemp.Replace(" #B ", "");
sTemp = sTemp.Replace("#B ", "");
sTemp = sTemp.Replace(" #B", "");
sTemp = sTemp.Replace("#B", "");
int numberOfLeak = 30 - sTemp.Length;
var x = 30 + numberOfLeak;
if (textBox1.Text.Length > x)
{
textBox1.Text = textBox1.Text.Insert(x, Environment.NewLine);
}
string oriText = textBox1.Text;//Original text that you input
int charPerLine = 30;//Number of character per line
string sKeyword = "#A|#B";//You can add more template here, the separator is "|"
string[] arrKeyword = sKeyword.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
ArrayList arrListKeyword = new ArrayList();
for (int i = 0; i < arrKeyword.Length; i++)
{
arrListKeyword.Add(" " + arrKeyword[i] + " ");
arrListKeyword.Add(arrKeyword[i] + " ");
arrListKeyword.Add(" " + arrKeyword[i]);
arrListKeyword.Add(arrKeyword[i]);
}
int nextIndex = 0;
while (true)
{
//Check if the sub string after the NewLine has enough length
if (charPerLine < oriText.Substring(nextIndex).Length)
{
string sSubString = oriText.Substring(nextIndex, charPerLine);
//Replace all keywords with the blank
for (int i = 0; i < arrListKeyword.Count; i++)
{
sSubString = sSubString.Replace(arrListKeyword[i].ToString(), "");
}
int numberOfLeak = charPerLine - sSubString.Length;
int newLineIndex = nextIndex + charPerLine + numberOfLeak;//find the index to insert NewLine
oriText = oriText.Insert(newLineIndex, Environment.NewLine);//Insert NewLine
nextIndex = newLineIndex + Environment.NewLine.Length;//Environment.NewLine cost 2 in length
}
else
{
break;
}
}
textBox1.Text = oriText;

Categories

Resources