I need a little help! I cannot figure out how to take the last three lines of a file and store each to a separate string. An array would work too if possible.
string[] lines = File.ReadAllLines(myfile);
If someone could use an array for this, how would I get only the last three lines. Please keep note that I do not know the length of the file!
Thanks
var last3lines = lines.Skip(lines.Length - 3).ToArray();
This seems a little too simple....
Update
In case the length of the array is less than 3 in size. This should either print the last three lines based on count, or less than three lines if i == -1
string[] lines = File.ReadAllLines(myFile)
// Get the last three lines
int count = 0;
for (int i = lines.length - 1; i >= 0; i++)
{
Console.WriteLine(lines[i]);
count++;
if (count == 3)
{
break;
}
}
For a way that does not require you to load all lines from the file in a big array with ReadAllLines, but just reads them a line at a time, keeping only the last (3) ones read, you can do:
var threeLines = new string[3];
var nLines = 0;
foreach (var line in File.ReadLines(myFile))
{
var ndx = nLines % 3;
threeLines[ndx] = line;
nLines++;
}
Also, this will not crash if you have less then 3 lines in your input.
for (var i = 0; i < Math.Min(nLines, 3); i++)
Console.WriteLine(threeLines[i]);
Or to get them in order of last, last-1, last-2:
for (var i = Math.Min(nLines, 3); i > 0; i--)
Console.WriteLine(threeLines[i-1]);
Inefficient but it works: lines.Reverse().Take(3).Reverse()
Alternative:
line1 = lines[lines.length-3] // Third to last
line2 = lines[lines.length-2]
line3 = lines[lines.length-1] // Last line
Related
I have a populated multi-line textbox that has a few thousand lines and occassionally has lines like this:
"e8eae9e8eae8e8ebe9e8c5c5c5eae9e8eae8e8ebe9e8eae9e8eae9e8eae8e8ebe9e8eae9e8eae9"
The values can be random, but the common denominator is that they always have over 25 characters and no spaces in the line. I would like to remove any line that meets this specification. I've tried writing the code below but it is giving me index errors.Anyone know of a good way to do this?
string[] lines = txtNotes.Lines;
List<string> tmp = new List<string>(lines);
for (int i = 0; i < lines.GetUpperBound(0); i++)
{
if ((lines[i].Length > 25) && (!(lines[i].Contains(" "))))
{
tmp.RemoveAt(i);
}
}
lines = tmp.ToArray();
txtNotes.Lines = lines;
When you call tmp.RemoveAt(i); the number elements in the tmp reduces so you can end up trying to remove element with an index that is not present in the list anymore.
You can switch your loop to run from last element to first:
for (int i = lines.Length -1 ; i > 0; i--)
{
if ((lines[i].Length>25) && (!(lines[i].Contains(" "))))
{
tmp.RemoveAt(i);
}
}
Or just use LINQ. Something like this:
txtNotes.Lines = txtNotes.Lines
.Where(l => l.Length <= 25 || l.Contains(" "))
.ToArray();
I want to make a program that finds how many times a key word has been repeated (i.e. "the") and then store the index position in a array. At the moment, my code only store's the first time it reads "the" in the string sentence. How do you make it that it stores the index position of the first time it reads "the" and the second?
It outputs on the console:
11
0
My current code:
string sentence = "John likes the snow and the winter.";
string keyWord = "the";
var test = sentence.Split(new char[] { ' ', '.' });
var count = Array.FindAll(test, s => s.Equals(keyWord.Trim())).Length;
int[] arr = new int[count];
for (int i = 0; i < arr.Length; i++)
{
arr[i] = sentence.IndexOf("the", i);
i++;
}
foreach (int num in arr)
{
Console.WriteLine(num);
}
Console.ReadLine();
Second result (0) is there because of unnecessary i++ in the for loop. Because of that, you are entering the loop only once. To achieve what you want you could try code like below (please take a closer look at body of the for loop:
string sentence = "John likes the snow and the winter.";
string keyWord = "the";
var test = sentence.Split(new char[] { ' ', '.' });
var count = Array.FindAll(test, s => s.Equals(keyWord.Trim())).Length;
int[] arr = new int[count];
int lastIndex = 0;
for (int i = 0; i < arr.Length; i++)
{
lastIndex = sentence.IndexOf("the", lastIndex + keyWord.Length); //We are adding length of the `keyWord`, because we want to skip word we already found.
arr[i] = lastIndex;
}
foreach (int num in arr)
{
Console.WriteLine(num);
}
Console.ReadLine();
I hope it makes sense.
There are two problems that I see with your code. First, you're incrementing i twice, so it will only ever get half the items. Second, you're passing i as the second parameter to IndexOf (which represents the starting index for the search). Instead, you should be starting the search after the previous found instance by passing in the index of the last instance found plus its length.
Here's a fixed example of the for loop:
for (int i = 0; i < arr.Length; i++)
{
arr[i] = sentence.IndexOf(keyword, i == 0 ? 0 : arr[i - 1] + keyword.Length);
}
Also, your code could be simplified a little if you use a List<int> instead of an int[] to store the indexes, because with List you don't need to know the count ahead of time:
string sentence = "John likes the snow and the winter.";
string keyWord = "the";
var indexes = new List<int>();
var index = 0;
while (true)
{
index = sentence.IndexOf(keyWord, index); // Find the next index of the keyword
if (index < 0) break; // If we didn't find it, exit the loop
indexes.Add(index++); // Otherwise, add the index to our list
}
foreach (int num in indexes)
{
Console.WriteLine(num);
}
I'm not very experienced when it comes to using .txt files in XNA and therefore i need some help.
I'm tring to make a Tile Engine read and put information depending on what number is in the .txt document. It looks something like this:
1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 etc
Now, this document contains 50 characters in X (25 without [ , ]) and has 15 lines in Y. The problem is that it only reads the first line in Y and not the other 14 remaining ones in Y, which is causing it to crash.
Here is the code:
public void LoadMap(string MapName)
{
using (StreamReader streamReader = new StreamReader("Content/" + MapName + ".txt"))
{
do
{
string line = streamReader.ReadLine();
string[] numbers = line.Split(',');
int temp = 0;
for (int y = 0; y < loopY; y++)
{
for (int x = 0; x < loopX; x++)
{
Blocks[y, x] = new Block();
//Crashes here when temp reaches 25
if (int.Parse(numbers[temp]) == 1)
Blocks[y, x].color = Color.Blue;
else if (int.Parse(numbers[temp]) == 2)
Blocks[y, x].color = Color.Violet;
else
Blocks[y, x].color = Color.White;
temp++;
}
}
} while (!streamReader.EndOfStream);
}
}
Based on your reply to my question:
"Index was outside the bounds of the array." Yes i checked it loopX is 25 and Numbers is 25
numbers[] is zero-indexed, so the upper bounds is numbers[24]. If loopX is 25 then, yes, you'll see an exception.
You're iterating through loopX and then loopY and incrementing temp every time. You'll either need to set temp back to 0 after each loopX iteration, or just use the numbers array instead of the loop values instead.
I suggest changing your loop to use numbers instead:
for (int x = 0; x < numbers.Length; x++)
And then, to use your existing code, check value using:
if (int.Parse(numbers[x]) == 1)
EDIT: This is what I was trying to explain:
using (StreamReader streamReader = new StreamReader("Content/" + MapName + ".txt"))
{
int y = 0;
do
{
string line = streamReader.ReadLine();
string[] numbers = line.Split(',');
for (int x = 0; x < numbers.Length; x++)
{
Blocks[y, x] = new Block();
if (int.Parse(numbers[x]) == 1)
Blocks[y, x].color = Color.Blue;
else if (int.Parse(numbers[x]) == 2)
Blocks[y, x].color = Color.Violet;
else
Blocks[y, x].color = Color.White;
}
y++;
} while (!streamReader.EndOfStream);
}
I see following things in your code, which seem suspicious to say the least:
If your temp >= numbers.Length, than you will get "Index was outside the bounds of the array".
If that happens after reading the first line, of course you will not read any further lines, because you got an exception and it will break.
You are overwriting your Blocks with every new line: If you read the first line and get into x and y loops, at the very first iteration of x and y, they will both be 0. So you write Blocks[0,0] = new Block(). After you read the next line, you get again into x and y loops. They start again with 0, so at the very first iteration of x and y while processing the second line you will write Blocks[0,0] = new Block(). Which will in fact overwrite the Block you wrote previously on index [0,0] during the handling of the first line. The same problem exists for all other combinations of x and y.
Debug, step-through and watch variables. That will help you understand what is going on.
i can't find any mistakes in my code.
here i'm trying to pick all numbers from the string:
(just to simplify the example,, i want to pick numbers that will satisfy some condition)
i use Queue cause i don't want to deal with array's indexes.
Console.Write("enter string: ");
string s = Console.ReadLine();
char[] array = s.ToCharArray();
Queue<char> q = new Queue<char>();
for (int i = 0; i < array.Length; i++)
{
q.Enqueue(array[i]);
}
char[] new_array = new char[q.Count];
for (int i = 0; i < q.Count; i++)
{
new_array[i] = q.Dequeue();
}
Console.WriteLine(new String(new_array));
Input string: 123456
And the output is a little weird:
123
another input: 123
output: 12
of course i made some mistake) but everything seems to be OK
Thank YOU in advance
The problem is the second loop:
for (int i = 0; i < q.Count; i++)
{
new_array[i] = q.Dequeue();
}
As q.Count decrements on every loop iteration, and i increases on every interation, you get only half of the elements.
try something like:
for (int i = 0; q.Count > 0; i++)
{
new_array[i] = q.Dequeue();
}
also consider: Queue.toArray
I would suggest using List<char> instead of Queue<char> and char[]. There's nothing here that particularly needs a queue, and it would avoid the problem that Rudolf pointed out, and a List is much easier to work with than an array. You can also use foreach instead of a for loop, and avoid the intermediate step.
Console.Write("enter string: ");
string s = Console.ReadLine();
List<char> new_array = new List<char>();
foreach(char c in s.ToCharArray())
{
new_array.Add(c);
}
Console.WriteLine(new String(new_array.ToArray()));
As the reason for your error is already stated,you can replace your two loops with just two statements
//A version of Queue constructor accepts IEnumerable object.
//you can directly pass the string to the queue constructor.
Queue<char> Que = new Queue<char>("123456");
//Copies the array and the position is preserved
var new_arr= Que.ToArray();
According to MSDN:
Removes and returns the object at the beginning of the Queue.
As you use Dequeue(), the q.Count value changes in each iteration.
So rather than using q.Count in this loop;
for (int i = 0; i < q.Count; i++)
use
int queueSize = q.Count;
for (int i = 0; i < queueSize; i++)
This will keep your looping limit as a constant number rather than calculating it in each iteration to find a different value because of using Dequeue().
I'm very new to C# (And Stack Overflow, forgive me for any poor etiquette here), and I'm writing the game Mastermind in a console application. I'm trying to show a list of the user's guesses at the end of the game, and I know that using Console.WriteLine(); will just give me 30-odd lines off numbers which don't tell the user anything.
How can I alter my code so that the program displays 4 numbers in a group, at a time? For example:
1234
1234
1234
//Store numbers in a history list
ArrayList guesses = new ArrayList(); //This is the ArrayList
Console.WriteLine("Please enter your first guess.");
guess1 = Convert.ToInt32(Console.ReadLine());
guesses.Add(guess1);
foreach (int i in guesses)
{
Console.Write(i);
}
I assume that each element of your byte array is a single digit (0-9). If that assumption is invalid -- please let me know, I'll modify the code :)
Action<IEnumerable<int>> dump = null;
dump = items =>
{
if(items.Any())
{
var head = String.Join("", items.Take(4));
Console.WriteLine(head);
var tail = items.Skip(4);
dump(tail);
}
};
dump(guesses);
It looks like you're most of the way there, you have a console write that writes them all out without linebreaks. Next add an integer count and set it to zero. Increment it by one in the foreach loop. count % 4 == 0 will then be true for all counts that are a multiple of four. This means you can stick an if block there with a write-line to give you your groups of four.
List<int> endResult = new List<int>();
StringBuilder tempSb = new StringBuilder();
for(int i=0; i < groups.Count; i++)
{
if(i % 4 == 0) {
endResult.Add(int.Parse(sb.ToString()));
tempSb.Clear(); // remove what was already added
}
tempSb.Append(group[i]);
}
// check to make sure there aren't any stragglers left in
// the StringBuilder. Would happen if the count of groups is not a multiple of 4
if(groups.Count % 4 != 0) {
groups.Add(int.Parse(sb.ToString()));
}
This will give you a list of 4 digit ints and make sure you don't lose any if your the number of ints in your groups list is not a multiple of 4. Please note that I am continuing based on what you provided, so groups is the ArrayList of ints.
This is some thing I quickly put together:
Update:
ArrayList guesses = new ArrayList(); //This is the ArrayList
// Four or more
guesses.Add(1); guesses.Add(2);
guesses.Add(3);guesses.Add(4);
guesses.Add(5); guesses.Add(6); guesses.Add(7);guesses.Add(8); guesses.Add(9);
//Uncomment-Me for less than four inputs
//guesses.Add(1); guesses.Add(2);
int position = 0;
if (guesses.Count < 4)
{
for (int y = 0; y < guesses.Count; y++)
{
Console.Out.Write(guesses[y]);
}
}
else
{
for (int i = 1; i <= guesses.Count; i++)
{
if (i%4 == 0)
{
Console.Out.WriteLine(string.Format("{0}{1}{2}{3}", guesses[i - 4], guesses[i - 3],
guesses[i - 2], guesses[i - 1]));
position = i;
}
else
{
if (i == guesses.Count)
{
for (int j = position; j < i; j++)
{
Console.Out.Write(guesses[j]);
}
}
}
}
}