Reversed chars - foreach loop - c#

I want to print the 3 lines of characters in reversed order but this example is done simply. How can I do it with foreach loop without using arrays?
public static void Main()
{
char firstInput = char.Parse(Console.ReadLine());
char secondInput = char.Parse(Console.ReadLine());
char thirdInput = char.Parse(Console.ReadLine());
Console.WriteLine(thirdInput.ToString() + " " + secondInput.ToString() + " " + firstInput.ToString());
}

You could create a method using the params keyword - not tested but something like:
private static string ReverseOrder(params char[] characters)
{
var result = "";
for (int i = characters.count; i > 0; i--)
{
result = result + characters[i];
}
return result;
}
and call like:
var reverseOrderResult = ReverseOrder(firstinput, secondinput, thirdinput);

Here's an attempt to follow the input conditions: no arrays and use of foreach loop (I'm sure the author isn't looking for something like this)
static void Main()
{
var result = "";
foreach (var c in NextInput(3))
{
result = c + " " + result;
}
Console.WriteLine(result);
}
private static IEnumerable<char> NextInput(int count)
{
var i = 0;
while (i++ < count)
yield return char.Parse(Console.ReadLine());
}

Related

Delete part of string value

I want to mix 2 string in 1 randomly using foreach but I don't know how I delete the part I used on the string for the foreach like:
string s = "idontknow";
string sNew = "";
foreach(char ss in s){
s = s + ss;
ss.Delete(s); //don't exist
}
Full code here i'm trying to do:
do
{
if (state == 0)
{
for (int i = 0; random.Next(1, 5) > variable.Length; i++)
{
foreach (char ch in variable)
{
fullString = fullString + ch;
}
}
state++;
}
else if (state == 1)
{
for (int i = 0; random.Next(1, 5) > numbers.Length; i++)
{
foreach (char n in numbers)
{
fullString = fullString + n;
}
}
state--;
}
} while (variable.Length != 0 && numbers.Length != 0);
I'm pretty confident, that in your first code snippet, you are creating an infinite loop, since you are appending the used char back to the string while removing it from the first position.
Regarding your specification to shuffle two stings together, this code sample might do the job:
public static string ShuffleStrings(string s1, string s2){
List<char> charPool = new();
foreach (char c in s1) {
charPool.Add(c);
}
foreach (char c in s2) {
charPool.Add(c);
}
Random rand = new();
char[] output = new char[charPool.Count];
for(int i = 0; i < output.Length; i++) {
int randomIndex = rand.Next(0, charPool.Count);
output[i] = charPool[randomIndex];
charPool.RemoveAt(randomIndex);
}
return new string(output);
}
In case you just want to shuffle one string into another string, just use an empty string as the first or second parameter.
Example:
string shuffled = ShuffleStrings("TEST", "string");
Console.WriteLine(shuffled);
// Output:
// EgsTtSnrTi
There are possibly other solutions, which are much shorter, but I think this code is pretty easy to read and understand.
Concerning the performance, the code above should works both for small stings and large strings.
Since strings are immutable, each modify-operation on any string, e.g. "te" + "st" or "test".Replace("t", ""), will allocate and create a new string in the memory, which is - in a large scale - pretty bad.
For that very reason, I initialized a char array, which will then be filled.
Alternatively, you can use:
using System.Text;
StringBuilder sb = new();
// append each randomly picked char
sb.Append(c);
// Create a string from appended chars
sb.ToString();
And if your question was just how to remove the first char of a string:
string myStr = "Test";
foreach (char c in myStr) {
// do with c whatever you want
myStr = myStr[1..]; // assign a substring exluding first char (start at index 1)
Console.WriteLine($"c = {c}; myStr = {myStr}");
}
// Output:
// c = T; myStr = est
// c = e; myStr = st
// c = s; myStr = t
// c = t; myStr =

How can i get index of two same character in string?

I want to create simple console wingman game.My error is that if i try get pos of 2 same character in word i get only one and the other is skipped.
For example Tomatoe.
Console output:
Tomatoe
_ o m a t _ _
I know i didnt use live didnt have time for that i do it layter.
class Program {
static string[] word = { "Pineapple", "Apple" , "Tomatoe" , "Pizza"};
static int wordIndex = 0;
static char[] randomWord;
static bool guessing = true;
public static void Main(string[] args)
{
int lives = 3;
Console.OutputEncoding = Encoding.UTF8;
Console.InputEncoding = Encoding.UTF8;
Random r = new Random();
wordIndex = r.Next(word.Length);
randomWord = word[wordIndex].ToLower().ToCharArray();
char[] randomWordcensored = new char[randomWord.Length];
for (int i = 0; i < randomWord.Length; i++)
{
randomWordcensored[i] = '_';
}
Console.WriteLine("Hello");
foreach (var item in randomWordcensored)
{
Console.Write(item + " ");
}
Console.WriteLine();
Console.WriteLine("Please Enter character:");
while (guessing = true)
{
int g = 0;
char userinput;
bool security = char.TryParse(Console.ReadLine() ,out userinput);
if (security == true) {
if (randomWord.Contains(userinput))
{ //help needed
g = (word[wordIndex].ToString().IndexOf(userinput) == -1 ? 0 : word[wordIndex].ToString().IndexOf(userinput));
randomWordcensored[g] = userinput;
Console.WriteLine("Good :) " + g);
foreach (var item in randomWordcensored)
{
Console.Write(item + " ");
}
}
else
{
lives--;
Console.WriteLine("Wrong!\n-Lives:" + lives);
}
}
else
{
Console.WriteLine("Enter only one charracter!");
}
}
}
}
You'll want to handle user input that might be different casing and such. Because of that it's easiest to just visit every character in the random word just once.
Here's a REPL that I made to solve this:
using System;
using System.Collections.Generic;
class MainClass {
public static void Main (string[] args) {
var word = "Tomato";
var input = "t";
var letter = input.ToLower()[0];
var indices = new List<int>();
for(var i = 0; i < word.Length; i++)
if (word.ToLower()[i] == letter)
indices.Add(i);
Console.WriteLine($"Secret word: {word}");
Console.WriteLine($"User guess: {input}");
Console.WriteLine($"Found at {String.Join(", ", indices)}");
}
}
and its output:
Mono C# compiler version 4.0.4.0
Secret word: Tomato
User guess: t
Found at 0, 4

English to Pig Latin C# Console Application

I'm having some trouble making an applicaton in c# converting english to pig latin. I have everything else down except for when it comes to making the getTranslation method for it. For some odd reason I just can't figure it out. IF someone could give me some ideas I would appreciate it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace W15M5A2_CPigLatinApp
{
class W15M5A2_CPigLatinAppProgram
{
static void Main(string[] args)
{
string inputPhrase = "";
string[] phraseOut;
DisplayInfo();
inputPhrase = GetPhrase();
while (inputPhrase != "")
{
Console.WriteLine(" ");
phraseOut = GetTranslation(inputPhrase);
DisplayResults(inputPhrase, phraseOut);
inputPhrase = GetPhrase();
}
Console.ReadKey();
}
public static void DisplayInfo()
{
Console.WriteLine("********************************************************" +
"\n*** You will be prompted to enter a string of ***" +
"\n*** words. The phrase will be converted into a ***" +
"\n*** pseudo Pig Latin with results displayed. ***" +
"\n\n*** Enter as many strings as you would like. ***" +
"\n********************************************************\n\n");
Console.Write("\n\n\n Press any key when you are ready to begin...");
Console.ReadKey();
Console.Clear();
}
public static string GetPhrase()
{
string inputPhrase;
Console.WriteLine("Enter a phrase or group of words " +
"\nTo Exit, press the Enter key\n");
inputPhrase = Console.ReadLine();
return inputPhrase;
}
// GetTranslation method
public static string[] GetTranslation(string phraseIn)
{
}
public static void DisplayResults(string input, string[] output)
{
Console.Clear();
Console.WriteLine("Original Phrase: " + input + "\n");
Console.Write("\nNew Phrase: ");
foreach (string i in output)
{
Console.Write(i + " ");
}
Console.WriteLine("\n");
}
}
}
public static string[] GetTranslation(string phraseIn)
{
string vow = "aeiouyAEIOUY";
var splitted = phraseIn.Split(new[] {" "}, StringSplitOptions.None);
List< string> ret = new List<string>();
foreach (string split in splitted)
{
string vows = string.Empty;
string cons = string.Empty;
for (var i = 0; i < split.Length; i++)
{
char ch = split[i];
if (vow.Contains(ch))
{
vows += ch;
}
else
{
cons += ch;
}
}
ret.Add(cons + vows + "ay");
}
return ret.ToArray();
}
This is a (little bit hacky) solution. I tested it with the examples from Wiki.
public static string ToPigLatin(string word)
{
string result = string.Empty;
string pigSuffixVowelFirst = "yay";
string pigSuffixConstanantsFirst = "ay";
string vowels = "aeiouAEIOU";
if(vowels.Contains(word.First()))
{
result = word + pigSuffixVowelFirst;
}
else
{
int count = 0;
string end = string.Empty;
foreach(char c in word)
{
if (!vowels.Contains(c))
{
end += c;
count++;
}
else
{
break;
}
}
result = word.Substring(count) + end + pigSuffixConstanantsFirst;
}
return result;
}
Use at your own peril :)

Best way to split string into lines with maximum length, without breaking words

I want to break a string up into lines of a specified maximum length, without splitting any words, if possible (if there is a word that exceeds the maximum line length, then it will have to be split).
As always, I am acutely aware that strings are immutable and that one should preferably use the StringBuilder class. I have seen examples where the string is split into words and the lines are then built up using the StringBuilder class, but the code below seems "neater" to me.
I mentioned "best" in the description and not "most efficient" as I am also interested in the "eloquence" of the code. The strings will never be huge, generally splitting into 2 or three lines, and it won't be happening for thousands of lines.
Is the following code really bad?
private static IEnumerable<string> SplitToLines(string stringToSplit, int maximumLineLength)
{
stringToSplit = stringToSplit.Trim();
var lines = new List<string>();
while (stringToSplit.Length > 0)
{
if (stringToSplit.Length <= maximumLineLength)
{
lines.Add(stringToSplit);
break;
}
var indexOfLastSpaceInLine = stringToSplit.Substring(0, maximumLineLength).LastIndexOf(' ');
lines.Add(stringToSplit.Substring(0, indexOfLastSpaceInLine >= 0 ? indexOfLastSpaceInLine : maximumLineLength).Trim());
stringToSplit = stringToSplit.Substring(indexOfLastSpaceInLine >= 0 ? indexOfLastSpaceInLine + 1 : maximumLineLength);
}
return lines.ToArray();
}
Even when this post is 3 years old I wanted to give a better solution using Regex to accomplish the same:
If you want the string to be splitted and then use the text to be displayed you can use this:
public string SplitToLines(string stringToSplit, int maximumLineLength)
{
return Regex.Replace(stringToSplit, #"(.{1," + maximumLineLength +#"})(?:\s|$)", "$1\n");
}
If on the other hand you need a collection you can use this:
public MatchCollection SplitToLines(string stringToSplit, int maximumLineLength)
{
return Regex.Matches(stringToSplit, #"(.{1," + maximumLineLength +#"})(?:\s|$)");
}
NOTES
Remember to import regex (using System.Text.RegularExpressions;)
You can use string interpolation on the match:
$#"(.{{1,{maximumLineLength}}})(?:\s|$)"
The MatchCollection works almost like an Array
Matching example with explanation here
How about this as a solution:
IEnumerable<string> SplitToLines(string stringToSplit, int maximumLineLength)
{
var words = stringToSplit.Split(' ').Concat(new [] { "" });
return
words
.Skip(1)
.Aggregate(
words.Take(1).ToList(),
(a, w) =>
{
var last = a.Last();
while (last.Length > maximumLineLength)
{
a[a.Count() - 1] = last.Substring(0, maximumLineLength);
last = last.Substring(maximumLineLength);
a.Add(last);
}
var test = last + " " + w;
if (test.Length > maximumLineLength)
{
a.Add(w);
}
else
{
a[a.Count() - 1] = test;
}
return a;
});
}
I reworked this as prefer this:
IEnumerable<string> SplitToLines(string stringToSplit, int maximumLineLength)
{
var words = stringToSplit.Split(' ');
var line = words.First();
foreach (var word in words.Skip(1))
{
var test = $"{line} {word}";
if (test.Length > maximumLineLength)
{
yield return line;
line = word;
}
else
{
line = test;
}
}
yield return line;
}
I don't think your solution is too bad. I do, however, think you should break up your ternary into an if else because you are testing the same condition twice. Your code might also have a bug. Based on your description, it seems you want lines <= maxLineLength, but your code counts the space after the last word and uses it in the <= comparison resulting in effectively < behavior for the trimmed string.
Here is my solution.
private static IEnumerable<string> SplitToLines(string stringToSplit, int maxLineLength)
{
string[] words = stringToSplit.Split(' ');
StringBuilder line = new StringBuilder();
foreach (string word in words)
{
if (word.Length + line.Length <= maxLineLength)
{
line.Append(word + " ");
}
else
{
if (line.Length > 0)
{
yield return line.ToString().Trim();
line.Clear();
}
string overflow = word;
while (overflow.Length > maxLineLength)
{
yield return overflow.Substring(0, maxLineLength);
overflow = overflow.Substring(maxLineLength);
}
line.Append(overflow + " ");
}
}
yield return line.ToString().Trim();
}
It is a bit longer than your solution, but it should be more straightforward. It also uses a StringBuilder so it is much faster for large strings. I performed a benchmarking test for 20,000 words ranging from 1 to 11 characters each split into lines of 10 character width. My method completed in 14ms compared to 1373ms for your method.
Try this (untested)
private static IEnumerable<string> SplitToLines(string value, int maximumLineLength)
{
var words = value.Split(' ');
var line = new StringBuilder();
foreach (var word in words)
{
if ((line.Length + word.Length) >= maximumLineLength)
{
yield return line.ToString();
line = new StringBuilder();
}
line.AppendFormat("{0}{1}", (line.Length>0) ? " " : "", word);
}
yield return line.ToString();
}
~6x faster than the accepted answer
More than 1.5x faster than the Regex version in Release Mode (dependent on line length)
Optionally keep the space at the end of the line or not (the regex version always keeps it)
static IEnumerable<string> SplitToLines(string stringToSplit, int maximumLineLength, bool removeSpace = true)
{
int start = 0;
int end = 0;
for (int i = 0; i < stringToSplit.Length; i++)
{
char c = stringToSplit[i];
if (c == ' ' || c == '\n')
{
if (i - start > maximumLineLength)
{
string substring = stringToSplit.Substring(start, end - start); ;
start = removeSpace ? end + 1 : end; // + 1 to remove the space on the next line
yield return substring;
}
else
end = i;
}
}
yield return stringToSplit.Substring(start); // remember last line
}
Here is the example code used to test speeds (again, run on your own machine and test in Release mode to get accurate timings)
https://dotnetfiddle.net/h5I1GC
Timings on my machine in release mode .Net 4.8
Accepted Answer: 667ms
Regex: 368ms
My Version: 117ms
My requirement was to have a line break at the last space before the 30 char limit.
So here is how i did it. Hope this helps anyone looking.
private string LineBreakLongString(string input)
{
var outputString = string.Empty;
var found = false;
int pos = 0;
int prev = 0;
while (!found)
{
var p = input.IndexOf(' ', pos);
{
if (pos <= 30)
{
pos++;
if (p < 30) { prev = p; }
}
else
{
found = true;
}
}
outputString = input.Substring(0, prev) + System.Environment.NewLine + input.Substring(prev, input.Length - prev).Trim();
}
return outputString;
}
An approach using recursive method and ReadOnlySpan (Tested)
public static void SplitToLines(ReadOnlySpan<char> stringToSplit, int index, ref List<string> values)
{
if (stringToSplit.IsEmpty || index < 1) return;
var nextIndex = stringToSplit.IndexOf(' ');
var slice = stringToSplit.Slice(0, nextIndex < 0 ? stringToSplit.Length : nextIndex);
if (slice.Length <= index)
{
values.Add(slice.ToString());
nextIndex++;
}
else
{
values.Add(slice.Slice(0, index).ToString());
nextIndex = index;
}
if (stringToSplit.Length <= index) return;
SplitToLines(stringToSplit.Slice(nextIndex), index, ref values);
}

Custom function for splitting string on Upper Case characters does not works as expected

public static string UpperCaseStringSplitter(string stringToSplit)
{
var stringBuilder = new StringBuilder();
foreach (char c in stringToSplit)
{
if (Char.IsUpper(c) && stringToSplit.IndexOf(c) > 0)
stringBuilder.Append(" " + c);
else
stringBuilder.Append(c);
}
return stringBuilder.ToString();
}
If I pass a string like this:
TestSrak
the output is the expected one : "Test Srak".
But when there are two same letters where one is lower case and the other is Uppercase next to each other, the split does not happen:
For example If the input is:
TestTruck
The output is also TestTruck . Can You please tell me where is the problem and how can I fix it. Thanks!
The problem is this
stringToSplit.IndexOf(c) > 0)
In "TestTruck" the first letter(index == 0) is also a T, therefore it will not enter the if.
Instead i would use a for-loop and check if the current char is the first, then you can skip the split:
for(int i=0; i < stringToSplit.Length; i++)
{
if (i > 0 && Char.IsUpper(stringToSplit[i]))
stringBuilder.Append(" ").Append(stringToSplit[i]);
else
stringBuilder.Append(stringToSplit[i]);
}
Try this:
public static string UpperCaseStringSplitter(string stringToSplit)
{
var stringBuilder = new StringBuilder();
for(int i = 0; i <stringToSplit.Length; i++)
{
char c = stringToSplit[i];
if (Char.IsUpper(c) && i > 0)
stringBuilder.Append(" " + c);
else
stringBuilder.Append(c);
}
return stringBuilder.ToString();
}
The problem with your code has been identified by Tim Schmelter's answer, but if you are trying to append a space before the upper case character in the string, then you can try the following (using LINQ)
string str = "TestTrak";
string newString = string.Join("",
str.Select(r=> char.IsUpper(r) ?" " + r: r.ToString()));
newString = newString.Trim(); //to remove space from the start
Try this:
if (string.IsNullOrWhiteSpace(stringToSplit)) return stringToSplit;
var stringBuilder = new StringBuilder();
for (int i = 0; i < stringToSplit.Length; i++)
{
if (Char.IsUpper(stringToSplit[i]))
{
stringBuilder.Append(" ");
}
stringBuilder.Append(stringToSplit[i]);
}
return stringBuilder.ToString().Trim();

Categories

Resources