Appending to StringBuilder while there is nothing left - c#

I have to the task to rearrange the words in a sentence backwards, but i am able to do it only for the first letter.Example: Fun exam right.What i have until now:
var sentance = Console.Readline().Split(' ');
var rearrangedSentence = new StringBuilder();
for(int i = 0,i<sentance.Lenght,i++)
{
rearrangedSentence.Append(sentance[i].Last());//this gives me "nmt"
}
My question is how to make this loop repeat itself while there is nothing left.
Any help will be greatly appriciated :)
EDIT: Question is
I mean if i have the sentence "Fun exam right" the result should be :nmtuahFxgeir . We first take the last chars of each word append that results in "nmt" then take the next one and add them resulting in "nmtuah" and so on

When you use sentance[i].Last(), you are only picking up the last element of your array.
EDIT: As per your updated requirements, you can use this code.
//Get the sentence array
var sentence = Console.ReadLine().Split(' ');
var rearrangedSentence = new StringBuilder();
//Get the length of longest word in array
int loopLength = sentence.OrderBy(n => n.Length).Last().Length;
int x = 0;
// Run for the length of longest word
for (int i = loopLength-1; i >=0 ; i--)
{
// need to pick up an element at every run for each element.
for (var j = 0; j < sentence.Length; j++)
{
//Picking the position of item to be picked up
int val = sentence[j].Length - (x + 1);
// If index not out of bounds
if(val >= 0 && val <= sentence[j].Length)
{
// Pick the character and append to stringbuilder.
rearrangedSentence.Append(sentence[j][val]);
}
}
// Next letter should be n-1, then n-2.
// Increase this. Val will decrease
x++;
}
Console.WriteLine(rearrangedSentence.ToString());
Console.ReadLine();

Related

Text from file to the end of 2d char array

I'm trying to solve the problem, but I just can't find the answer.
It is required to read a names.txt file, consisting of 5 words. After that, needs to convert them into char and then put the left side of the matrix and the bottom (look picture down). Other empty spaces need to fill with symbol "+".
I've tried many variations, but it doesn't display correctly.
Please help!
String txtFromFile = File.ReadAllText(#"C:\Users\source\names.txt");
Console.WriteLine("Words from file:\n{0}", txtFromFile);
int rows = 10;
int column = 10;
char[,] charArray = new char[rows, column];
for (int a = 0; a < rows; a++)
{
for (int b = 0; b < column; b++)
{
charArray[a, b] = '+';
Console.Write(string.Format("{0} ", charArray[a, b]));
}
Console.Write(Environment.NewLine + Environment.NewLine);
}
If you are inexperienced with Linq her is a solution without using it.
int rows = 10;
int column = 10;
int lineCount = 0; //pointer variable to be used when padding lines with +
string emptyLine = "";
emptyLine = emptyLine.PadRight(column, '+'); //create empty line string
string[] lines = File.ReadLines(#"C:\Users\source\names.txt").ToArray(); //read all lines and store in a string array variable
//add lines with only +
for (int row = 0; row < rows - lines.Length; row++)
{
Console.WriteLine(emptyLine);
}
//loop through all read lines and pad them
foreach (string line in lines)
{
lines[lineCount] = lines[lineCount].Replace(line, line.PadRight(column, '+')); //pad the line and replace it in the collection
Console.WriteLine(lines[lineCount]);
lineCount++;
}
This solution uses string instead of char[]. However, if you need to get the array you can simply find it in the read lines collection by
char[] charArray = lines[i].ToCharArray();
for an arbitrary index i in the read lines collection.
You can do it in one Line,
using System.Linq;
...
//Read all lines instead of reading all inputs in form of text.
//Note: Expecting all words should be are stored on different line.
string[] txtFromFile = File.ReadAllLines(#"C:\Users\source\names.txt");
var result = Enumerable.Range(0, 10) //Iterate for 10 lines
.Select(x => x < 5 // Check for line number
? new string('+', 10) //If line is from 0..4, then print ++++++++++
: txtFromFile[x-5].PadRight(10, '+') //else print word then pad it with ++
);
//Print the result
Console.WriteLine(string.Join(Environment.NewLine, result));
.NET Fiddle
output:
++++++++++
++++++++++
++++++++++
++++++++++
++++++++++
DOG+++++++
SHEEP+++++
CHIMPANZEE
BREAVER+++
LION++++++

Finding the longest word (and write it out) in string without split, distinct and foreach [duplicate]

This question already has answers here:
Finding longest word in string
(4 answers)
Closed 3 years ago.
I got an assignment to make a method to find the longest word in a string without split, distinct and foreach.
I was able to split the words and count the length but I am stuck on how can I actually compare and write them out.
static void Main(string[] args)
{
String s1 = "Alex has 2 hands.";
longestWord(s1);
Console.
}
static void longestWord(String s1)
{
char emp = ' ';
int count = 0;
char[] ee = s1.ToCharArray();
for (int i = 0; i < ee.Length; i++)
{
if (ee[i] == emp || ee[i] == '.')
{
count++;
Console.Write(" " + (count-1));
Console.WriteLine();
count = 0;
}
else
{
Console.Write(ee[i]);
count++;
}
}
}
The output right now looks like this:
Alex 4
has 3
2 1
hands 5
I am pretty sure I would be able to get only the longest number to show by comparing count before reset with temp int but how to write out the word with it.
Or if there is a easier way which probably is.
You are already on a good way. Instead of directly printing the words, store the length and position of the longest word and print it at the end. Like so:
static void longestWord(String s1)
{
char emp = ' ';
int longestLength = 0;
int longestStart = 0;
int currentStart = 0;
for (int i = 0; i < s1.Length; i++)
{
if (s1[i] == emp || s1[i] == '.')
{
// calculate the current word length
int currentLength = i - currentStart;
// test if this is longer than the currently longest
if(currentLength > longestLength)
{
longestLength = currentLength;
longestStart = currentStart;
}
// a new word starts at the next character
currentStart = i + 1;
}
}
// print the longest word
Console.WriteLine($"Longest word has length {longestLength}: \"{s1.Substring(longestStart, longestLength)}\"");
}
There is no need for the .ToCharArray(). You can access the string directly.
I will question whether you are actually supposed to treat "2" as a word and count it at all. Using regular expressions will allow you to approach the problem using a LINQ one-liner:
static void Main(string[] args)
{
String s1 = "Alex has 2 hands.";
var word = longestWord(s1);
Console.WriteLine(word);
//Console.ReadLine();
}
static string longestWord(string s1) {
return Regex.Matches(s1,"[A-Za-z]+") // find all sequences containing alphabetical characters, you can add numberas as well: [A-Za-z0-9]
.Cast<Match>() // cast results to Enumberable<Match> so we can apply LINQ to it
.OrderByDescending(m => m.Length) // luckily for us, Match comes with Length, so we just sort our results by it
.Select(m => m.Value) // instead of picking up everything, we only want the actual word
.First(); // since we ordered by descending - first item will be the longest word
}
You can store for every word the chars in new list of chars (list for dynamic length)
and if the new word is longer of the prev long word convert it to string.
If you have two word in same length it will take the first.
If you want the last change the "maxLength < count" to "maxLength <= count"
static string longestWord(String s1)
{
char emp = ' ';
int count = 0;
int maxLength = 0;
string maxWord = string.Empty;
List<char> newWord = new List<char>();
char[] ee = s1.ToCharArray();
for (int i = 0; i < ee.Length; i++)
{
if (ee[i] == emp || ee[i] == '.')
{
if (maxLength < count)
{
maxLength = count;
maxWord = new string(newWord.ToArray());
}
count = 0;
newWord = new List<char>();
}
else
{
newWord.Add(ee[i]);
count++;
}
}
return maxWord;
}

Find all possible combinations of word with and without hyphens

For a string that may have zero or more hyphens in it, I need to extract all the different possibilities with and without hyphens.
For example, the string "A-B" would result in "A-B" and "AB" (two possibilities).
The string "A-B-C" would result in "A-B-C", "AB-C", "A-BC" and "ABC" (four possibilities).
The string "A-B-C-D" would result in "A-B-C-D", "AB-C-D", "A-BC-D", "A-B-CD", "AB-CD", "ABC-D", "A-BCD" and "ABCD" (eight possibilities).
...etc, etc.
I've experimented with some nested loops but haven't been able to get anywhere near the desired result. I suspect I need something recursive unless there is some simple solution I am overlooking.
NB. This is to build a SQL query (shame that SQL Server does't have MySQL's REGEXP pattern matching).
Here is one attempt I was working on. This might work if I do this recursively.
string keyword = "A-B-C-D";
List<int> hyphens = new List<int>();
int pos = keyword.IndexOf('-');
while (pos != -1)
{
hyphens.Add(pos);
pos = keyword.IndexOf('-', pos + 1);
}
for (int i = 0; i < hyphens.Count(); i++)
{
string result = keyword.Substring(0, hyphens[i]) + keyword.Substring(hyphens[i] + 1);
Response.Write("<p>" + result);
}
A B C D are words of varying length.
Take a look at your sample cases. Have you noticed a pattern?
With 1 hyphen there are 2 possibilities.
With 2 hyphens there are 4 possibilities.
With 3 hyphens there are 8 possibilities.
The number of possibilities is 2n.
This is literally exponential growth, so if there are too many hyphens in the string, it will quickly become infeasible to print them all. (With just 30 hyphens there are over a billion combinations!)
That said, for smaller numbers of hyphens it might be interesting to generate a list. To do this, you can think of each hyphen as a bit in a binary number. If the bit is 1, the hyphen is present, otherwise it is not. So this suggests a fairly straightforward solution:
Split the original string on the hyphens
Let n = the number of hyphens
Count from 2n - 1 down to 0. Treat this counter as a bitmask.
For each count begin building a string starting with the first part.
Concatenate each of the remaining parts to the string in order, preceded by a hyphen only if the corresponding bit in the bitmask is set.
Add the resulting string to the output and continue until the counter is exhausted.
Translated to code we have:
public static IEnumerable<string> EnumerateHyphenatedStrings(string s)
{
string[] parts = s.Split('-');
int n = parts.Length - 1;
if (n > 30) throw new Exception("too many hyphens");
for (int m = (1 << n) - 1; m >= 0; m--)
{
StringBuilder sb = new StringBuilder(parts[0]);
for (int i = 1; i <= n; i++)
{
if ((m & (1 << (i - 1))) > 0) sb.Append('-');
sb.Append(parts[i]);
}
yield return sb.ToString();
}
}
Fiddle: https://dotnetfiddle.net/ne3N8f
You should be able to track each hyphen position, and basically say its either there or not there. Loop through all the combinations, and you got all your strings. I found the easiest way to track it was using a binary, since its easy to add those with Convert.ToInt32
I came up with this:
string keyword = "A-B-C-D";
string[] keywordSplit = keyword.Split('-');
int combinations = Convert.ToInt32(Math.Pow(2.0, keywordSplit.Length - 1.0));
List<string> results = new List<string>();
for (int j = 0; j < combinations; j++)
{
string result = "";
string hyphenAdded = Convert.ToString(j, 2).PadLeft(keywordSplit.Length - 1, '0');
// Generate string
for (int i = 0; i < keywordSplit.Length; i++)
{
result += keywordSplit[i] +
((i < keywordSplit.Length - 1) && (hyphenAdded[i].Equals('1')) ? "-" : "");
}
results.Add(result);
}
This works for me:
Func<IEnumerable<string>, IEnumerable<string>> expand = null;
expand = xs =>
{
if (xs != null && xs.Any())
{
var head = xs.First();
if (xs.Skip(1).Any())
{
return expand(xs.Skip(1)).SelectMany(tail => new []
{
head + tail,
head + "-" + tail
});
}
else
{
return new [] { head };
}
}
else
{
return Enumerable.Empty<string>();
}
};
var keyword = "A-B-C-D";
var parts = keyword.Split('-');
var results = expand(parts);
I get:
ABCD
A-BCD
AB-CD
A-B-CD
ABC-D
A-BC-D
AB-C-D
A-B-C-D
I've tested this code and it is working as specified in the question. I stored the strings in a List<string>.
string str = "AB-C-D-EF-G-HI";
string[] splitted = str.Split('-');
List<string> finalList = new List<string>();
string temp = "";
for (int i = 0; i < splitted.Length; i++)
{
temp += splitted[i];
}
finalList.Add(temp);
temp = "";
for (int diff = 0; diff < splitted.Length-1; diff++)
{
for (int start = 1, limit = start + diff; limit < splitted.Length; start++, limit++)
{
int i = 0;
while (i < start)
{
temp += splitted[i++];
}
while (i <= limit)
{
temp += "-";
temp += splitted[i++];
}
while (i < splitted.Length)
{
temp += splitted[i++];
}
finalList.Add(temp);
temp = "";
}
}
I'm not sure your question is entirely well defined (i.e. could you have something like A-BCD-EF-G-H?). For "fully" hyphenated strings (A-B-C-D-...-Z), something like this should do:
string toParse = "A-B-C-D";
char[] toParseChars = toPase.toCharArray();
string result = "";
string binary;
for(int i = 0; i < (int)Math.pow(2, toParse.Length/2); i++) { // Number of subsets of an n-elt set is 2^n
binary = Convert.ToString(i, 2);
while (binary.Length < toParse.Length/2) {
binary = "0" + binary;
}
char[] binChars = binary.ToCharArray();
for (int k = 0; k < binChars.Length; k++) {
result += toParseChars[k*2].ToString();
if (binChars[k] == '1') {
result += "-";
}
}
result += toParseChars[toParseChars.Length-1];
Console.WriteLine(result);
}
The idea here is that we want to create a binary word for each possible hyphen. So, if we have A-B-C-D (three hyphens), we create binary words 000, 001, 010, 011, 100, 101, 110, and 111. Note that if we have n hyphens, we need 2^n binary words.
Then each word maps to the output you desire by inserting the hyphen where we have a '1' in our word (000 -> ABCD, 001 -> ABC-D, 010 -> AB-CD, etc). I didn't test the code above, but this is at least one way to solve the problem for fully hyphenated words.
Disclaimer: I didn't actually test the code

Im trying scramble randomaly strings but some of the strings dosen't get scrambled at all what could it be?

This is the code:
private static StringBuilder MakeRandomwords(string theWord)
{
var jumbleSb = new StringBuilder();
jumbleSb.Append(theWord);
int lengthSb = jumbleSb.Length;
for (int i = 0; i < lengthSb; ++i)
{
int index1 = (RandomGen.Next() % lengthSb);
int index2 = (RandomGen.Next() % lengthSb);
Char temp = jumbleSb[index1];
jumbleSb[index1] = jumbleSb[index2];
jumbleSb[index2] = temp;
}
return jumbleSb;
}
And this is the List that im using to build the scrambled words:
private void GetText()
{
_lengthaboveone = new List<string>();
for (int i = 0; i < _words.Count; i++)
{
string word = _words[i];
if (word.Length < 4) continue;
string first = word.Substring(0, 1);
string last = word.Substring(word.Length - 1, 1);
string middle = word.Substring(1, word.Length - 2);
_lengthaboveone.Add(middle);
_words[i] = first + MakeRandomwords(middle) + last;
}
_scrambledWords = _words;
}
In the end the List _scrambledWords contain over 1000 strings in each index a string of a word most of them scrambled but some of them are left the same as they were in the original.
The question is if there is something wrong with my MakeRandomwords ?
Could be it did scrambled the word and it was scrambled to how it was before ? So maybe i need to add something to the code that will keep scramble the word untill the word is scrambled by compraing it ot the original untill the word is scrambled ?
Take a look at the Fisher–Yates shuffle algorithm and implement the following pseudo code to achieve a good distribution of elements:
To shuffle an array a of n elements (indices 0..n-1):
for i from n − 1 downto 1 do
j ← random integer with 0 ≤ j ≤ i
exchange a[j] and a[i]
To elaborate on Tim Schmelter's comment asking about RandomGen.Next(), in case you've been wondering: If you instantiate a new Random instance every time you're entering the for loop, the generated pseudo-random numbers will by nature be quite repetitive. This is due to the way that the Random class is implemented in the .NET framework. By reusing a shared instance like you do, one can avoid that issue.
This is not the problem here, though. In your algorithm, you're picking two random array elements and swapping them. It's highly likely that there are some array elements that never get selected this way. Thus, there's a good chance that some elements won't have changed their position in the array when you're done, which is why it doesn't look shuffled well.
Instead of randomly swapping two locations, swap every location to a random location... it will look more random because each element will have moved. With your current design there is a good chance some items won't ever move.
for (int i = 0; i < lengthSb; ++i)
{
int index1 = i;
int index2 = (RandomGen.Next() % lengthSb);
Char temp = jumbleSb[index1];
jumbleSb[index1] = jumbleSb[index2];
jumbleSb[index2] = temp;
}

Searching for a phrase

I've got an array of words, which are taken from a sentence (each word in the sentence is placed in an array).
A user can search for a phrase to see if it's found in this sentence. This is to be determined through the characters' offset values. This means that each word is checked to see if it exists in the phrase, separately, then a check is carried out to see if the words come after each other or not (separated by a space in the sentence).
The words are stored in a tree, and thus the offset values (character position) is the only thing which determines which word comes after which (and is separated by a space).
My problem is that words which are the same (and already stored in the tree) have the same offset values, and thus each word stores a data structure of all offset valuesattributed with the specific word. This is the code I've got so far, which works perfectly except that it fails in the following case:
For example I've got this sentence: this is a test to see if this is working.
If I search for 'this is a', then the first this is is returned as well as this is a.
Here's the code:
for (int i = 0; i < offsets.Count - 1; i++)
{
LinkedList<int> current = allOffsets[i];
LinkedList<int> next = allOffsets[i + 1];
for (int j = 0; j < current.Count; j++)
{
for (int k = 0; k < next.Count; k++)
{
if (current.ElementAt(j) + words[i].Length - 1 + 2 == next.ElementAt(k))
{
if (!finalResult.Contains(current.ElementAt(j)))
{
finalResult.Add(current.ElementAt(j));
}
if (!finalResult.Contains(next.ElementAt(k)))
{
finalResult.Add(next.ElementAt(k));
}
}
}
}
}
return finalResult;
Please note that finalResult is a list which stores all the 'valid' offsets, and offsets stores all the offsets in the tree. words is an array which contains all the words after they're split from the sentence.
EDIT: Also please note that I'm checking to see if the words follow each other by adding the offset of the first letter of a word by 2 (to account for the space) and this will be equal to the offset of the first letter of the next word, if it follows.
var source = new List<string>() { "this", "is", "a", "test", "to", "see", "if", "this", "is", "working" };
var userInput = "this is a";
var inputList = userInput.Split(' ');
var inputListCount = inputList.Count();
var exists = false;
for (int i = 0; i < source.Count; i++)
{
if (inputList[0] == source[i])
{
var found = true;
for (int j = 1; j < inputListCount; j++)
{
if (inputList[j] != source[j])
{
found = false;
break;
}
}
if (found)
{
exists = true;
break;
}
}
}
Console.WriteLine(exists);

Categories

Resources