randomly select a line in a textfile c# streamreader

1.9k views Asked by At

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.
        }
5

There are 5 answers

0
Austin Salonen On

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.

0
driis On

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.

0
Ben On

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".

1
Jon Skeet On

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;
    }
}
0
Linora On

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;
    }
}