I am reading in a text file which consists of a grid of alpha-numeric values (see below).
IQQQQQ
WG2223
S22228
D22223
Currently these values are looped through and each character sent to a switch case. This switch then reads that character and outputs a given result. The code for this process is as follows.
private void LoadLevel(Stream stream)
{
List<string> lines = new List<string>();
uint width;
using (StreamReader reader = new StreamReader(stream))
{
string line = reader.ReadLine();
width = (uint)line.Length;
while (line != null)
{
lines.Add(line);
line = reader.ReadLine();
}
}
tiles = new Tile[width, lines.Count];
for (int y = 0; y < Height; ++y)
{
for (int x = 0; x < Width; ++x)
{
char type = lines[y][x];
tiles[x, y] = LoadTile(type, x, y);
}
}
}
In this code I retrieve the text file and store each line in a list and then loop through each line and extract each character at a given point in the grid. Rather than extract a single character I would like to extract two characters at the same time and pass this to the LoadTile function.
As an example take the first line of the grid.
IQQQQQ
I would like to split this line into three strings each two characters long and then pass that to LoadTile and then continue looping through the remainder of the grid. However I do not know where to begin to attempt to achieve this task. Any help would be appreciated.
Well first off you'll propably want to change the signature of LoadTile from LoadTile(char, int, int) to LoadTile(string, int, int). Then change the calculation of the width to
width = line.Length/2;
Of course if any line has an odd number of characters you'll lose the last character. Additionally if any line after the first is shorter you'll have exceptions and if it is longer you'll lose the additional data.
Then you can loop through like this and take substrings.
for (int y = 0; y < Height; ++y)
{
for (int x = 0; x < Width; ++x)
{
string type = lines[y].Substring(x*2,2);
tiles[x, y] = LoadTile(type, x, y);
}
}
You can do this:
var str = "IQQQQQ";
var arr = Regex.Matches(str, "..").Cast<Match>().ToArray().Select(u => u.Value);
// arr[0] = "IQ"
// arr[1] = "QQ"
// arr[2] = "QQ"
This is how you get a substring:
var item = source.Substring(i * 2, 2);
You can split to array in one line:
var split = Enumerable.Range(0,3).Select(i=>source.Substring(i * 2, 2)).ToArray();
for (var i = 0; i < 3; i++)
{
var item = split[i];
// ...
}
Using LinQ. Try doing this for every line:
//Converts the string to a List of strings
List<string> stringArray = line.ToCharArray().Select(c=>c.ToString()).ToList();
//Iterates over the list and concats every pair of elements
List<string> result = stringArray.Select((value, index) => new { value, index })
.GroupBy(x => x.index / 2, x => x.value).Select(pair => pair.Aggregate((s1,s2) => s1 + s2)).ToList();
Related
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++++++
I have an array of string elements of various words. I need the characters of each word be split equally into the text component of 3 buttons. For example, the array could hold the elements "maybe", "his", "car". In each game one of these words will be pulled from the array and its characters divided into the 3 buttons. For example, button 1 will have "ma", button 2 will have "yb" and button 3 "e" (for the word maybe). I then hide the text element of one button for the user to drag and drop the correct missing letter(s) into the space. The purpose of the game is to help children learn to spell. Does anyone know how I could go about dividing the characters equally into the 3 buttons?
Here's a function that would split the word into the amount of segments you want. You can then iterate over that list to set each segment to a button.Text.
public List<string> SplitInSegments(string word, int segments)
{
int wordLength = word.Length;
// The remainder tells us how many segments will get an extra letter
int remainder = wordLength % segments;
// The base length of a segment
// This is a floor division, because we're dividing ints.
// So 5 / 3 = 1
int segmentLength = wordLength / segments;
var result = new List<string>();
int startIndex = 0;
for (int i = 0; i < segments; i++)
{
// This segment may get an extra letter, if its index is smaller then the remainder
int currentSegmentLength = segmentLength + (i < remainder ? 1 : 0);
string currentSegment = word.Substring(startIndex, currentSegmentLength);
// Set the startindex for the next segment.
startIndex += currentSegmentLength;
result.Add(currentSegment);
}
return result;
}
usage:
// returns ["ma", "yb", "e"]
var segments = SplitInSegments("maybe", 3);
Edit
I like the fact that this is for teaching children. So here comes.
Regarding your question on splitting the string based on specific letter sequences: After you've split the string using regex, you will have an array of strings. Then determine the amount of items in the splitted string and concatenate or split further based on the number of segments:
// sequences to split on first
static readonly string[] splitSequences = {
"el",
"ol",
"bo"
};
static readonly string regexDelimiters = string.Join('|', splitSequences.Select(s => "(" + s + ")"));
// Method to split on sequences
public static List<string> SplitOnSequences(string word)
{
return Regex.Split(word, regexDelimiters).Where(s => !string.IsNullOrEmpty(s)).ToList();
}
public static List<string> SplitInSegments(string word, int segments)
{
int wordLength = word.Length;
// The remainder tells us how many segments will get an extra letter
int remainder = wordLength % segments;
// The base length of a segment
// This is a floor division, because we're dividing ints.
// So 5 / 3 = 1
int segmentLength = wordLength / segments;
var result = new List<string>();
int startIndex = 0;
for (int i = 0; i < segments; i++)
{
// This segment may get an extra letter, if its index is smaller then the remainder
int currentSegmentLength = segmentLength + (i < remainder ? 1 : 0);
string currentSegment = word.Substring(startIndex, currentSegmentLength);
// Set the startindex for the next segment.
startIndex += currentSegmentLength;
result.Add(currentSegment);
}
return result;
}
// Splitword will now always return 3 segments
public static List<string> SplitWord(string word)
{
if (word == null)
{
throw new ArgumentNullException(nameof(word));
}
if (word.Length < 3)
{
throw new ArgumentException("Word must be at least 3 characters long", nameof(word));
}
var splitted = SplitOnSequences(word);
var result = new List<string>();
if (splitted.Count == 1)
{
// If the result is not splitted, just split it evenly.
result = SplitInSegments(word, 3);
}
else if (splitted.Count == 2)
{
// If we've got 2 segments, split the shortest segment again.
if (splitted[1].Length > splitted[0].Length
&& !splitSequences.Contains(splitted[1]))
{
result.Add(splitted[0]);
result.AddRange(SplitInSegments(splitted[1], 2));
}
else
{
result.AddRange(SplitInSegments(splitted[0], 2));
result.Add(splitted[1]);
}
}
else // splitted.Count >= 3
{
// 3 segments is good.
result = splitted;
// More than 3 segments, combine some together.
while (result.Count > 3)
{
// Find the shortest combination of two segments
int shortestComboCount = int.MaxValue;
int shortestComboIndex = 0;
for (int i = 0; i < result.Count - 1; i++)
{
int currentComboCount = result[i].Length + result[i + 1].Length;
if (currentComboCount < shortestComboCount)
{
shortestComboCount = currentComboCount;
shortestComboIndex = i;
}
}
// Combine the shortest segments and replace in the result.
string combo = result[shortestComboIndex] + result[shortestComboIndex + 1];
result.RemoveAt(shortestComboIndex + 1);
result[shortestComboIndex] = combo;
}
}
return result;
}
Now when you call the code:
// always returns three segments.
var splitted = SplitWord(word);
Here is another approach.
First make sure that the word can be divided by the desired segments (add a dummy space if necessary) , then use a Linq statement to get your parts and when adding the result trim away the dummy characters.
public static string[] SplitInSegments(string word, int segments)
{
while(word.Length % segments != 0) { word+=" ";}
var result = new List<string>();
for(int x=0; x < word.Count(); x += word.Length / segments)
result.Add((new string(word.Skip(x).Take(word.Length / segments).ToArray()).Trim()));
return result.ToArray();
}
You can split your string into a list and generate buttons based on your list. The logic for splitting the word into a string list would be something similar to this:
string test = "maybe";
List list = new List();
int i = 0, len = 2;
while(i <= test.Length)
{
int lastIndex = test.Length - 1;
list.Add(test.Substring(i, i + len > lastIndex? (i + len) - test.Length : len));
i += len;
}
HTH
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();
I am attempting to read (n) amount of random lines from a text file with about 200 entries (lines) and populate a listbox called "recSongs". I have provided some simple code which retrieves one random line from the text file, but I want retrieve n amount.
Here is my code.
var lines = File.ReadAllLines(#"file.txt");
var r = new Random();
var randomLineNumber = r.Next(0, lines.Length - 1);
var line = lines[randomLineNumber];
recSongs.Items.Add(line);
How about:
var lines = File.ReadAllLines("file.txt").OrderBy(x => Guid.NewGuid()).Take(n);
n will be the input , i.e no of lines you need
List <string> text = File.ReadLines("file.txt").Take(n).ToList();
Edit
If you need random lines, you could do,
string[] lines = File.ReadAllLines(#"C:\YourFile.txt");
List<string> source = new List<string>();
int n = 10;
for (int i = 0; i < n; i++)
{
source.Add(lines[new Random().Next(lines.Length)]);
}
var lines = File.ReadAllLines(#"file.txt");
var r = new Random();
var randomized = lines.OrderBy(item => r.Next()); //randomize the list
recSongs.Items.AddRange(randomized.Take(N).ToArray()); //Add N amount to listbox
This solution also avoids duplicate randoms
Probably the easiest way, though not the most memory-efficient, is to slurp the file into an in-memory collection of its lines, then Shuffle() the lines and take however many you want:
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> input)
{
var buffer = input.ToArray();
//Math.Random is OK for "everyday" randomness;
//use RNGCryptoServiceProvider if you need
//cryptographically-strong randomness
var rand = new Random();
//As the loop proceeds, the element to output will be randomly chosen
//from the elements at index i or above, which will then be swapped
//with i to get it out of the way; the yield return gives us each
//shuffled value as it is chosen, and allows the shuffling to be lazy.
for (int i = 0; i < buffer.Length; i++)
{
int j = rand.Next(i, buffer.Length);
yield return buffer[j];
//if we cared about the elements in the buffer this would be a swap,
//but we don't, so...
buffer[j] = buffer[i];
}
}
...
string[] fileLines = GetLinesFromFile(fileName); //a StreamReader makes this pretty easy
var randomLines = fileLines.Shuffle().Take(n);
Some notes:
This should work fairly well for a text file of about 200 lines; beyond a couple hundred thousand lines, you'll start having memory problems. A more scalable solution would be to shuffle an array of line numbers, then use those to seek for and read the specific lines you want, discarding all the others.
This solution produces the random lines in random order. If you want to preserve the order of the lines from the file, do the line-number variant, sorting the line numbers you select, then just keep the lines in that order after reading them out of the file.
Try this
var lines = File.ReadAllLines(#"file.txt");
var r = new Random();
int noLines = 10;// n lines
for (int i = 0; i < noLines; i++)
{
var randomLineNumber = r.Next(0, lines.Length - 1);
var line = lines[randomLineNumber];
recSongs.Items.Add(line);
}
You could do something like:
HashSet<int> linesHash = new HashSet<int>();
var lines = file.ReadLines();
for (int i = 0; i < numLinesToGet; i++)
{
int line=0;
do
{
line = rand.Next(0, lines.Length);
}while(linesHash.Contains(line));
linesHash.Add(line);
linesAdded.Add(lines[line]);
}
Note that if the amount of lines to get is greater than the actually number of lines my code would never end, so some checks must be done prior to execute the for loop.
This will add numLines random lines to your collection. Note that there is a chance that there will be duplicates.
var lines = File.ReadAllLines(#"file.txt");
var r = new Random();
int numLines = 5;
for (int i = 0; i < numLines; i++)
{
recSongs.Items.Add(lines[r.Next(0, lines.Length - 1)]);
}
To enforce unique items, you could do something like this:
for (int i = 0; i < numLines; i++)
{
var randomItem = string.Empty;
do
{
randomItem = lines[r.Next(0, lines.Length - 1)];
} while (recSongs.Contains(randomItem));
recSongs.Items.Add(randomItem);
}
But now note that it is possible that it will never exit. The joys of Random!
var lines = File.ReadAllLines(#"file.txt");
var random = new Random();
var lines = Enumerable.Repeat( -1, n ) // -1 is a filler and is discarded by the select.
.Select( _ => random.Next(0, lines.Length - 1 ) )
.Select( index => lines[index] );
foreach( var line in lines )
{
recSongs.Items.Add(line);
}
I am stuck in this case,
i have to compare a row of a two dimensional array to a one dimensional array. both arrays have characters like + and - and D. to be usable both arrays (the row and the single array) should match perfectly, but if any have the character D (for doubtful) it should be considered as inclusive
eg.
{+,-,d} compared to {+,-,-},
{+,-,d},
{+,d,d}
the program should return the row numbers of 2 and 3.
Something like that?
var mat = new[,] {{'-','+','d'},{'-','-','d'},{'-','d','+'}};
var arr = new[] {'d','-','+'};
var matHeight = mat.GetLength(0);
var validRows = new List<int>();
for (int y = 0; y < matHeight; y++)
{
bool isRowValid = true;
for (int x = 0; x < arr.Length; x++)
{
if (mat[y, x] != 'd' && arr[x] != 'd' && mat[y, x] != arr[x])
{
isRowValid = false;
break;
}
}
if (isRowValid)
{
validRows.Add(y);
}
}
foreach (var y in validRows)
{
Console.WriteLine("Row {0} is valid", y);
// will print 1 and 2 (two last rows indices)
}
I suggest using array of arrays (jagged array) rather than two dimensional array, though.