I want to write the result of var item in text file.
I use File.WriteAllText, the path is #"C:\Users\TBM\Desktop\test.txt"
but I only get the last value of item, which is EDC
static void Main(string[] args)
{
var alphabet = "ABCDE";
var q = alphabet.Select(x => x.ToString());
int size = 3;
for (int i = 0; i < size - 1; i++)
{
q = q.SelectMany(x => alphabet, (x, y) => x + y);
}
foreach (var item in q)
{
if ((item[0] == item[1]) || (item[1] == item[2]) || (item[0] == item[2]))
{
continue;
File.WriteAllText(#"C:\Users\TBM\Desktop\test.txt", item);
}
}
}
The StreamWriter is the easiest way to write to a text file while you're looping through something:
using (var sw = new StreamWriter(filename))
{
foreach (something in somethingElse)
{
string line = "compute this line somehow";
sw.WriteLine(line);
}
}
That's all you need - your file will be created, written, saved, and closed.
File.WriteAllText() opens the file, writes your text to it then closes the file. You need to lookup one of the many examples of writing a text file line by line.
WriteAllText Overrites the entire contents of the text file with that item. The smallest change would be to change your code to use AppendAllText instead (clearing the file before the loop if that's what you want), but the more idomatic solution is to refactor your code to use WriteAllLines:
File.WriteAllLines(path, q);
That will simply write each item out on its own line.
Your File.WriteAllText() call in your example comes after continue -- how does it ever get invoked? It needs to be outside your if brackets.
should it be
foreach (var item in q)
{
if ((item[0] == item[1]) || (item[1] == item[2]) || (item[0] == item[2]))
{
continue;
}
File.WriteAllText(#"C:\Users\TBM\Desktop\test.txt", item);
}
Doesn't continue keyword skip the rest of the loop body?
Related
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
What does "Object reference not set to an instance of an object" mean? [duplicate]
(8 answers)
Closed 2 years ago.
I keep getting the error in title. I am not very experienced in coding and am not great at reading code and understanding it yet.
I also know this will be a simple fix but still I don't know what or where I need to fix.
using System;
using System.Linq;
namespace Day_6
{
class Program
{
static void Main(string[] args)
{
int numStrings = Convert.ToInt32(Console.ReadLine());
var str = "";
string[] words = new string[1000];
var even = new string[500];
var odd = new string[500];
for (int i = 0; i < numStrings; i++)
{
str = Console.ReadLine();
words.Append(str);
}
foreach (var word in words)
{
foreach (var letter in word)
{
if (word.IndexOf(letter)%2 != 0)
{
odd.Append(letter.ToString());
}
else
{
even.Append(letter.ToString());
}
}
Console.WriteLine(odd + " " + even);
}
}
}
}
Any help, even if it is just material to read so I can understand why/what/where I am getting this error would be great.
After all I am trying to learn!
Many thanks
If you have to use Arrays like you are doing, change your assignment for loop to the following,
for (int i = 0; i < numStrings; i++)
{
str = Console.ReadLine();
words[i] = str; // Assign to elements of Array (not Append).
}
and then you want to iterate over words that are not null (initial array is all nulls). You will need to use index for each of the even and odd arrays as well. You cannot use indexOf either to check if your character is even or odd... if you do that, then any duplicate letter will not work. Use an iteration index for that as well.
int evenIndex = 0;
int oddIndex = 0;
int iterationIndex = 0;
foreach (var word in words.Where(x => x != null))
{
foreach (var letter in word)
{
if (iterationIndex++ % 2 != 0)
{
odd[oddIndex++] = (letter.ToString());
}
else
{
even[evenIndex++] = (letter.ToString());
}
}
}
// Print this "outside" of your for loops
Console.WriteLine(string.Concat(odd.Where(x => x != null)) + " " + string.Concat(even.Where(x => x != null)));
You will also need to change your Console.WriteLine statement at the end to print the elements of the arrays instead of printing the type of the string array.
Console.WriteLine(string.Concat(odd.Where(x => x != null)) + " --- " + string.Concat(even.Where(x => x != null)));
Test Inputs and output
2
abababababababababababababab
abababababababababababababab
bbbbbbbbbbbbbbbbbbbbbbbbbbbb aaaaaaaaaaaaaaaaaaaaaaaaaaaa
Alternate Suggestion that doesnt use indexers
foreach (string word in words.Where(x => x != null))
{
for (int i = 0; i < word.Count(); i++)
{
if (i % 2 == 0)
odd[i] = word[i].ToString();
else
even[i] = word[i].ToString();
}
}
The first instance of null-reference error is caused by line 17 where you have words.Append(str);, replace it with words[i] = str;.
Read about the behaviour of IEnumerable.Append() method here, because it does not modify the array words in place; it returns a new IEnumerable, which must then be enumerated to an array.
So the statement words.Append(str); actually does nothing; if you wish to use the Append() method, you must save it's return value and enumerate the result to an array like so:
words = words.Append(str).ToArray()
Also, there's a second null-reference error in the 3rd statement in your Main() method (line 9), where you have
string[] words = new string[1000];
If you replace it with:
string[] words = new string[numStrings];
You will remove the possibility of your foreach loop looping over null elements.
i am new to c# and i am working on an app that display the time difference from two date on the last two line on a text file.
I want to read the before last line from a file text, i already know how to read the last line but i need to read the before last.
This is my code :
var lastLine = File.ReadAllLines("C:\\test.log").Last();
richTextBox1.Text = lastLine.ToString();
All the previous answers eagerly load all the file up in memory before returning the requested last lines. This can be an issue if the file is big. Luckily, it is easily avoidable.
public static IEnumerable<string> ReadLastLines(string path, int count)
{
if (count < 1)
return Enumerable.Empty<string>();
var queue = new Queue<string>(count);
foreach (var line in File.ReadLines(path))
{
if (queue.Count == count)
queue.Dequeue();
queue.Enqueue(line);
}
return queue;
}
This will only keep in memory the last n read lines avoiding memory issues with large files.
Since
File.ReadAllLines("C:\\test.log");
returns an array you can take the last two items of the array:
var data = File.ReadAllLines("C:\\test.log");
string last = data[data.Length - 1];
string lastButOne = data[data.Length - 2];
In general case with long files (and that's why ReadAllLines is a bad choice) you can implement
public static partial class EnumerableExtensions {
public static IEnumerable<T> Tail<T>(this IEnumerable<T> source, int count) {
if (null == source)
throw new ArgumentNullException("source");
else if (count < 0)
throw new ArgumentOutOfRangeException("count");
else if (0 == count)
yield break;
Queue<T> queue = new Queue<T>(count + 1);
foreach (var item in source) {
queue.Enqueue(item);
if (queue.Count > count)
queue.Dequeue();
}
foreach (var item in queue)
yield return item;
}
}
...
var lastTwolines = File
.ReadLines("C:\\test.log") // Not all lines
.Tail(2);
You can try to do this
var lastLines = File.ReadAllLines("C:\\test.log").Reverse().Take(2).Reverse();
But depending on how large your file is there are probably more efficient methods to process this than reading all lines at once. See Get last 10 lines of very large text file > 10GB and How to read last ānā lines of log file
Simply store the result of ReadAllLines to a variable and than take the two last ones:
var allText = File.ReadAllLines("C:\\test.log");
var lastLines = allText.Skip(allText.Length - 2);
You can use Skip() and Take() like
var lastLine = File.ReadAllLines("C:\\test.log");
var data = lastLine.Skip(lastLine.Length - 2);
richTextBox1.Text = lastLine.ToString();
You can use StreamReader in a combination of Queue<string> since you have to read whole file either way.
// if you want to read more lines change this to the ammount of lines you want
const int LINES_KEPT = 2;
Queue<string> meQueue = new Queue<string>();
using ( StreamReader reader = new StreamReader(File.OpenRead("C:\\test.log")) )
{
string line = string.Empty;
while ( ( line = reader.ReadLine() ) != null )
{
if ( meQueue.Count == LINES_KEPT )
meQueue.Dequeue();
meQueue.Enqueue(line);
}
}
Now you can just use these 2 lines like such :
string line1 = meQueue.Dequeue();
string line2 = meQueue.Dequeue(); // <-- this is the last line.
Or to add this to the RichTextBox :
richTextBox1.Text = string.Empty; // clear the text
while ( meQueue.Count != 0 )
{
richTextBox1.Text += meQueue.Dequeue(); // add all lines in the same order as they were in file
}
Using File.ReadAllLines will read the whole text and then using Linq will iterate through already red lines. This method does everything in one run.
string line;
string[] lines = new string[]{"",""};
int index = 0;
using ( StreamReader reader = new StreamReader(File.OpenRead("C:\\test.log")) )
{
while ( ( line = reader.ReadLine() ) != null )
{
lines[index] = line;
index = 1-index;
}
}
// Last Line -1 = lines[index]
// Last line = lines[1-index]
I'm working on an ASP mvc application and i'm trying to get all the next lines when previous line contains a word
I've used the code below but i just can get the last line that contains the word given
int counter = 0;
string line;
List<string> found = new List<string>();
// Read the file and display it line by line.
System.IO.StreamReader file = new System.IO.StreamReader("C:\\Users\\Chaimaa\\Documents\\path.txt");
while ((line = file.ReadLine()) != null)
{
if (line.Contains("fact"))
{
found.Add(line);
}
foreach (var i in found)
{
var output = i;
ViewBag.highlightedText = output;
}
}
Any help on what should I add to
1- get ALL lines that contains the word
2- and preferably get the ALL NEXT lines
You can use an overload of Where that provides an index, store indexes in a hash set, and use the containment check to decide if a line should be kept or not, like this:
var seen = new HashSet<int>();
var res = data.Where((v, i) => {
if (v.Contains("fact")) {
seen.Add(i);
}
return seen.Contains(i-1);
});
Demo.
As a side benefit, seen would contain indexes of all lines where the word "fact" has been found.
You can write a PairWise method that takes in a sequence of values and returns a sequence containing each item paired with the item that came before it:
public static IEnumerable<Tuple<T, T>> Pairwise<T>(this IEnumerable<T> source)
{
using (var iterator = source.GetEnumerator())
{
if (!iterator.MoveNext())
yield break;
T prev = iterator.Current;
while (iterator.MoveNext())
{
yield return Tuple.Create(prev, iterator.Current);
prev = iterator.Current;
}
}
}
With this method we can pair off each of the lines, get the lines where the previous value contains a word, and then project out the second value, which is the line after it:
var query = lines.Pairwise()
.Where(pair => pair.Item1.Contains(word))
.Select(pair => pair.Item2);
Hi I am reading from a text file and would like each line to be put into a seperate variable. From what I remember from my programming classes arrays cannot be dynamic. So if I set 15 arrays, and the text file has 1000 lines what can I do and how do I implement it.
The thing is only one line will be needed but I want the line to be randomly selected. the linetext is the whole text file with \r\n appended to the end of every request.
Maybe randomly select the \r\n then count 4 and add the string after it till the next \r\n. The problem with this idea is the strings getting called will also contain \ so any ideas?
if (crawler == true)
{
TextReader tr = new StreamReader("textfile.txt");
while (tr.Peek() != -1)
{
linktext = linktext + tr.ReadLine() + "\r\n";
}
//link = linktext;
hi.Text = linktext.ToString();
timer1.Interval = 7000; //1000ms = 1sec 7 seconds per cycle
timer1.Tick += new EventHandler(randomLink); //every cycle randomURL is called.
timer1.Start(); // start timer.
}
File.ReadAllLines(...) will read every line of the given file into an array of strings. I think that should be what you want but your question is kind of hard to follow.
You don't need to keep more than two lines in memory at a time... there's a sneaky trick you can use:
Create an instance of Random, or take one as a parameter
Read the first line. This automatically becomes the "current" line to return
Read the second line, and then call Random.Next(2). If the result is 0, make the second line the "current" line
Read the third line, and then call Random.Next(3). If the result is 0, make the third line the "current" line
... etc
When you reach the end of the file (reader.ReadLine returns null) return the "current" line.
Here's a general implementation for an IEnumerable<T> - if you're using .NET 4, you can use File.ReadLines() to get an IEnumerable<string> to pass to it. (This implementation has a bit more in it than is really needed - it's optimized for IList<T> etc.)
public static T RandomElement<T>(this IEnumerable<T> source,
Random random)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
if (random == null)
{
throw new ArgumentNullException("random");
}
ICollection collection = source as ICollection;
if (collection != null)
{
int count = collection.Count;
if (count == 0)
{
throw new InvalidOperationException("Sequence was empty.");
}
int index = random.Next(count);
return source.ElementAt(index);
}
ICollection<T> genericCollection = source as ICollection<T>;
if (genericCollection != null)
{
int count = genericCollection.Count;
if (count == 0)
{
throw new InvalidOperationException("Sequence was empty.");
}
int index = random.Next(count);
return source.ElementAt(index);
}
using (IEnumerator<T> iterator = source.GetEnumerator())
{
if (!iterator.MoveNext())
{
throw new InvalidOperationException("Sequence was empty.");
}
int countSoFar = 1;
T current = iterator.Current;
while (iterator.MoveNext())
{
countSoFar++;
if (random.Next(countSoFar) == 0)
{
current = iterator.Current;
}
}
return current;
}
}
A List<T> is a dynamically expanding list. You might want to use that instead of an array.
If there is only 1000 elements, just read them into the list and select a random element.
Regarding the array thing.. you could use a List<> instead, which is dynamic
Here is an example of how this can be achieved:
public static string GetRandomLine(ref string file) {
List<string> lines = new List<string>();
Random rnd = new Random();
int i = 0;
try {
if (File.Exists(file)) {
StreamReader reader = new StreamReader(file);
while (!(reader.Peek() == -1))
lines.Add(reader.ReadLine());
i = rnd.Next(lines.Count);
reader.Close();
reader.Dispose();
return lines[i].Trim();
}
else {
return string.Empty;
}
}
catch (IOException ex) {
MessageBox.Show("Error: " + ex.Message);
return string.Empty;
}
}
If you create the file then the ideal way would be to store meta data about the file, like the number of lines, before hand, and then decide which 'random' line to choose.
Otherwise, you cant get around the "array" problem by not using them. Instead use a List which stores any number of strings. After that picking a random one is as simple as generating a random number between 0 and the size of the list.
Your problem has been done before, I recommend googling for "C# read random line from file".
I am trying to figure out how to split a file by the number of lines in each file. THe files are csv and I can't do it by bytes. I need to do it by lines. 20k seems to be a good number per file. What is the best way to read a stream at a given position? Stream.BaseStream.Position? So if I read the first 20k lines i would start the position at 39,999? How do I know I am almost at the end of a files? Thanks all
using (System.IO.StreamReader sr = new System.IO.StreamReader("path"))
{
int fileNumber = 0;
while (!sr.EndOfStream)
{
int count = 0;
using (System.IO.StreamWriter sw = new System.IO.StreamWriter("other path" + ++fileNumber))
{
sw.AutoFlush = true;
while (!sr.EndOfStream && ++count < 20000)
{
sw.WriteLine(sr.ReadLine());
}
}
}
}
int index=0;
var groups = from line in File.ReadLines("myfile.csv")
group line by index++/20000 into g
select g.AsEnumerable();
int file=0;
foreach (var group in groups)
File.WriteAllLines((file++).ToString(), group.ToArray());
I'd do it like this:
// helper method to break up into blocks lazily
public static IEnumerable<ICollection<T>> SplitEnumerable<T>
(IEnumerable<T> Sequence, int NbrPerBlock)
{
List<T> Group = new List<T>(NbrPerBlock);
foreach (T value in Sequence)
{
Group.Add(value);
if (Group.Count == NbrPerBlock)
{
yield return Group;
Group = new List<T>(NbrPerBlock);
}
}
if (Group.Any()) yield return Group; // flush out any remaining
}
// now it's trivial; if you want to make smaller files, just foreach
// over this and write out the lines in each block to a new file
public static IEnumerable<ICollection<string>> SplitFile(string filePath)
{
return File.ReadLines(filePath).SplitEnumerable(20000);
}
Is that not sufficient for you? You mention moving from position to position,but I don't see why that's necessary.