How can I divide string into 3 parts? - c#

I want ask something about split string. Example:
string str = "1,2,3,4,5,6,7,8,9,10";
I want to divide str into 3 parts so parts look like:
string str1 = "1,2,3";
string str2 = "4,5,6";
string str3 = "7,8,9,10";
How can I do this?

You can try this
public static string SplitString(string data,int size)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
if (i % size == 0)
sb.Append(' ');
sb.Append(data[i]);
}
return sb.ToString();
}

Try following :
int size = 3;
string str = "1,2,3,4,5,6,7,8,9,10";
string[] splitArray = str.Split(new char[] { ',' }).ToArray();
string[] results = splitArray.Select((x,i) => new { index = i, number = x})
.GroupBy(x => (x.index < size * (splitArray.Length/size)) ? (x.index / (splitArray.Length/size)) : (x.index / (splitArray.Length/size)) - 1)
.Select(x => string.Join(",", x.Select(y => y.number)))
.ToArray();

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;
}

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

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

Get Last Four word after splitting a string

I have two string like below
var str1 = '20180215.20150215.3.1.0.0';
var str2 = '20180215.3.1.0.0';
I need to get the last four word after splitting these string with .
var str1Arr = str1.split('.')
What i need is a generic method to get last four words 3.1.0.0.
Thanks
var lastFour = str1Arr.Reverse().Take(4).Reverse().ToArray();
public static class SplitExtension
{
public static string LastNItems(this string str, int nItem, char separator = '.')
{
return string.Join(separator.ToString(), str.Split(separator).Reverse().Take(nItem).Reverse());
}
public static string[] LastNItems(this string[] strArray, int nItem)
{
return strArray.Reverse().Take(nItem).Reverse().ToArray();
}
}
This will enable you to do
var str1 = "20180215.20150215.3.1.0.0";
var str1Last4 = str1.LastNItems(4); // "3.1.0.0"
var str1Last4Items = str1.Split('.').LastNItems(4); // ["3","1","0","0"]
or for completion
var str1Last4Items = str1.LastNItems(4).Split('.'); // ["3","1","0","0"]
You can use it by extension methods.
public static class CommonExtension
{
public static List<string> LastNItem(this string str, int nItem, string separator = ".")
{
var splittedWords = str.Split(new [] { separator }, StringSplitOptions.None);
var res = splittedWords.Reverse().Take(nItem).Reverse().ToList();
return res;
}
}
Then you can call it everywhere you want.
var str1 = "1.0.0";
var str2 = "20180215.3.1.0.0";
var str1Last4 = str1.LastNItem(4);
var str2Last4 = str2.LastNItem(4);
Why not just Skip top Length - 4 items?
string str1 = "20180215.20150215.3.1.0.0";
string[] str1Arr = str1.Split('.');
var result = str1Arr
.Skip(str1Arr.Length - 4)
.ToArray(); // if you want an array materialization
This code will do even when str1Arr.Length < 4 (in this case the entire str1Arr copy will be returned). In case you want a string as the result you can just try Substring (without creating any arrays)
string str1 = "20180215.20150215.3.1.0.0";
string result = str1;
int index = result.Length;
for (int i = 0; i < 4; ++i) {
index = str1.LastIndexOf('.', index - 1);
if (index < 0)
break;
}
result = index < 0 ? result : result.Substring(index + 1);
public static string GetLastFour(string str)
{
string[] arr = str.Split('.');
System.Text.StringBuilder lastFour = new System.Text.StringBuilder();
if (arr.Length >= 4)
{
for (int k = arr.Length - 4; k < arr.Length; k++)
{
if (k == arr.Length - 1)
{
lastFour.Append(arr[k]);
}
else
{
lastFour.Append(arr[k] + ".");
}
}
}
return lastFour.ToString();
}
This would be faster than double reverse answer.
var str1 = "20180215.20150215.3.1.0.0";
var str2 = "20180215.3.1.0.0";
var words = str1.Split('.');
var toSkip = words.Length - 4;
var result = string.Join(".", words.Skip(toSkip));
A bit of testing showed that is is just slightly faster than double reverse.
What is 10 times faster than this one?
Well avoiding memory allocations and enumerations will be.
Here are the results of comparing 3 different extension methods for 10M iterations:
double reverse: 6463ms
split + skip: 5269ms
straight: 492ms
void Main()
{
var str1 = "20180215.20150215.3.1.0.0";
var numIterations = 10000000;
var timer = new Stopwatch();
timer.Start();
for (var i = 0; i < numIterations; i++)
{
str1.LastNItemsDoubleReverse(4);
}
timer.Stop();
timer.ElapsedMilliseconds.Dump("double reverse");
timer.Reset();
timer.Start();
for (var i = 0; i < numIterations; i++)
{
str1.LastNItemsSplitNSkip(4);
}
timer.Stop();
timer.ElapsedMilliseconds.Dump("split + skip");
timer.Reset();
timer.Start();
for (var i = 0; i < numIterations; i++)
{
str1.LastNItemsStraight(4);
}
timer.Stop();
timer.ElapsedMilliseconds.Dump("straight");
}
public static class ext
{
public static string LastNItemsDoubleReverse(this string str, int nItem, char separator = '.')
{
return string.Join(separator.ToString(), str.Split(separator).Reverse().Take(nItem).Reverse());
}
public static string LastNItemsSplitNSkip(this string str, int nItem, char separator = '.')
{
var words = str.Split(separator);
var toSkip = words.Length - nItem;
return string.Join($"{separator}", words.Skip(toSkip));
}
public static string LastNItemsStraight(this string str, int nItem, char separator = '.')
{
int j=1,i=str.Length-1;
for (;i>=0 && j<nItem;i--){
if(str[i]==separator) j++;
}
return str.Substring(i);
}
}
Try the following :
List<string> GetLastFourWords()
{
List<string> lastFour = new List<string>();
try
{
string[] arr = str1.split('.');
for(int i = 3; i >= 0; i-- )
{
lastFour.Add(arr[str1.length - 1 - i]);
}
}
catch(Exception ex)
{
}
return lastFour;
}

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);

split string around newline after some interval

I am trying to make some logic, but it is not ful proof yet:
string s = "1234567877y";
StringBuilder sb = new StringBuilder(s);
for (int i = 5; i <= s.Length + (s.Length / 5 ); i += 5 + (s.Length / 5) )
{
sb.Insert(i, Environment.NewLine);
}
Console.WriteLine(sb.ToString());
Console.ReadKey();
Output should be:
12345
67877
y
StringBuilder contain: "12345\r\n67877\r\ny"
But if i change input string i am not getting desired result. What i can do here or suggest some other way around.
EDIT:
if i change
string s = "1234567877y3434";
output will be
12345
67877y
3434
Another concise approach is using GroupBy:
string s = "1234567877y";
IEnumerable<string> groups = s.Select((c, index) => new{ c, index })
.GroupBy(x => x.index / 5)
.Select(xg => string.Join("", xg.Select(x => x.c)));
string result = string.Join(Environment.NewLine, groups);
Here is an approach with a StringBuilder which is more efficient:
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.Length; i++)
{
if ((i+1) % 5 == 0)
sb.Append(s[i]).Append(Environment.NewLine);
else
sb.Append(s[i]);
}
i would do it this way :)
string s = "1234567877y3434";
for (int i = 5; i < s.Length; i += 5 + Environment.NewLine.Length)
{
s = s.Substring(0, i) + Environment.NewLine + s.Substring(i, s.Length - i);
}
EDIT: i corrected my code using the suggstestion from Chris using Environment.NewLine instead of \r\n

Categories

Resources