How to Get a Random Line of a Text File in Java

How to get a random line of a text file in Java?

Here's a solution. Take a look at the choose() method which does the real thing (the main() method repeatedly exercises choose(), to show that the distribution is indeed quite uniform).

The idea is simple: when you read the first line it has a 100% chance of being chosen as the result. When you read the 2nd line it has a 50% chance of replacing the first line as the result. When you read the 3rd line it has a 33% chance of becoming the result. The fourth line has a 25%, and so on....

import java.io.*;
import java.util.*;

public class B {

public static void main(String[] args) throws FileNotFoundException {
Map<String,Integer> map = new HashMap<String,Integer>();
for(int i = 0; i < 1000; ++i)
{
String s = choose(new File("g:/temp/a.txt"));
if(!map.containsKey(s))
map.put(s, 0);
map.put(s, map.get(s) + 1);
}

System.out.println(map);
}

public static String choose(File f) throws FileNotFoundException
{
String result = null;
Random rand = new Random();
int n = 0;
for(Scanner sc = new Scanner(f); sc.hasNext(); )
{
++n;
String line = sc.nextLine();
if(rand.nextInt(n) == 0)
result = line;
}

return result;
}
}

How to grab a random line from a text file and print the line

Here is a quick idea. Note I have not tested this code. Just put it together really quick... And this should be sufficient only for small files. If you need to handle larger amounts of data, then I would suggest just reading the file to the line of interest (based on random) and processing only that line. Moreover, other libs may help specifically with this problem (e.g., Apache commons: FileUtils.readLines(file).get(indexNumber))

FileInputStream fs= new FileInputStream("quotes.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fs));
ArrayList<String> array = new ArrayList<>();
String line;
while((line = br.readLine()) != null)
array.add(line);
// variable so that it is not re-seeded every call.
Random rand = new Random();

// nextInt is exclusive. Should be good with output for array.
int randomIndex = rand.nextInt(array.size());

// Print your random quote...
System.out.println(array.get(randomIndex));

Print random line from text file in java

The answer boils down to your for loop condition and when you are calling nextLine().

Starting off with nextLine(), you are currently only calling nextLine() when you reach the numbered line you want. However, you need to advance the "pointer" in the file to reach that line as well, otherwise, you will only read the first line of the file when you call it. This is compounding with the next issue though:

Second, because your for loop condition is i <= wordNumber, you are continuing to loop when you finally do get to that line number, but because you don't increment i again once you reach the number you want (you don't have i++ inside your else if code), it is always evaulating to true (i == wordNumber) and keeps looping. You can see below I've put the incrementing of i into the third position of the for loop so that it always increments.

for(int i = 1; i <= wordNumber; i++){
String secretWord = wordListNew.nextLine();
if (i == wordNumber){
System.out.println(secretWord);
}
}

Get a random line from a text file in assets folder

This post is old, but I have the solution on who cannot progress with making passwords using a wordlist.

Obviously, first, read the file (can be from Storage or Assets) and test if that works. If this works, then create a random number picker and paste this following code:

public static int getRandomNumber(int min, int max) {
return new Random().nextInt(max - min + 1) + min;
}

To get a random word out of the Wordlist, use

String[] lines = content.split(System.lineSeparator());
int random = getRandomNumber(0, lines.length);
String word = lines[random];

And to generate a new password, it is recommended to use while to loop, until it hits the minimal length (currentPassword is a String and I copied the code from my project (see on my GitHub page))

private void generateNewPassword() {
currentPassword = "";

while (currentPassword.length() <= minLength)
currentPassword += lines[Utility.getRandomNumber(0, lines.length - 1)] + charsBetweenWords;

if (replacesChars) {
for (int i = 0; i < listFrom.size(); i++) {
if (replacesCases) {
String lowercase = listFrom.get(i).toLowerCase();
String uppercase = listFrom.get(i).toUpperCase();

currentPassword = currentPassword.replaceAll(lowercase, listTo.get(i));
currentPassword = currentPassword.replaceAll(uppercase, listTo.get(i));
} else {
if (listTo.get(i).equals("$"))
currentPassword = currentPassword.replaceAll(listFrom.get(i), "\\$");
else if (listFrom.get(i).equals("$"))
currentPassword = currentPassword.replaceAll("\\$", listTo.get(i));
else if (listTo.get(i).equals("\\"))
currentPassword = currentPassword.replaceAll(listFrom.get(i), "\\");
else if (listFrom.get(i).equals("\\"))
currentPassword = currentPassword.replaceAll("\\\\", listTo.get(i));
else
currentPassword = currentPassword.replaceAll(listFrom.get(i), listTo.get(i));
}
}
}

currentPassword = currentPassword.substring(0, currentPassword.length() - charsBetweenWords.length());

passwordOutput.setText(currentPassword);
}

selecting random lines from huge text file

There are several things that I find troublesome about your current code.

  1. You are currently loading the entire file into RAM. I don't know much about your sample file, but the one I used crashed my default JVM.
  2. You are skipping the same lines over and over again, more so for the earlier lines - this is horribly inefficient, like O(n^n) or something. I would be surprised if you could handle even a 500MB file with that approach.

Here's what I came up with:

public static void main(String[] args) throws IOException {
int sampleSize = 3000;
int fileSize = 50000;
int[] linesNumber = new int[sampleSize];
Random r = new Random();
for (int i = 0; i < linesNumber.length; i++) {
linesNumber[i] = r.nextInt(fileSize);

}
List<Integer> list = Arrays.stream(linesNumber).boxed().collect(Collectors.toList());
Collections.sort(list);

BufferedWriter outputWriter = Files.newBufferedWriter(Paths.get("localOutput/output.txt"));
long t1 = System.currentTimeMillis();
try(BufferedReader reader = new BufferedReader(new FileReader("extremely large file.txt")))
{
int index = 0;//keep track of what item we're on in the list
int currentIndex = 0;//keep track of what line we're on in the input file
while(index < sampleSize)//while we still haven't finished the list
{
if(currentIndex == list.get(index))//if we reach a line
{
outputWriter.write(reader.readLine());
outputWriter.write("\n");//readLine doesn't include the newline characters
while(index < sampleSize && list.get(index) <= currentIndex)//have to put this here in case of duplicates in the list
index++;
}
else
reader.readLine();//readLine is dang fast. There may be faster ways to skip a line, but this is still plenty fast.
currentIndex++;
}
} catch (Exception e) {
System.err.println(e);
}
outputWriter.close();
System.out.println(String.format("Took %d milliseconds", System.currentTimeMillis() - t1));
}

This takes ~87 milliseconds for me on a 4.7GB file running with a sample size of 30 and filesize of 50000 and took ~91 milliseconds when I changed the sample size to 3000. It took 122 milliseconds when I increased the filesize to 10,000. Tl;Dr for this paragraph = it scales pretty well, and it scales extremely well with larger sample sizes.

In direct answer to your question "is there more elegant faster method to do this?" Yes, there is. The faster way to do it is to skip lines yourself, don't load the entire file into memory, and make sure to keep using buffered readers and writers. Also, I'd avoid trying to do your own raw Array buffers or anything like that - just don't.

Feel free to step through the method I've included if you want to see more of how it works.

How can I display a random line from a text file?

I suggest you use a buffered reader. With in.readLine() you can get your next line from the file.

Math.random() generated a (pseudo) random number between 0 and 1. By multiplying and casting to int you generate a number between 0 and 100. If that random number happens to be of a specific value (50 in this case) you stop your loop and print the line.

You can change the odds of the loop breaking by changing the multiplication factor to anything you like. Just make sure to compare to a number in your specified range.

BufferedReader in = new BufferedReader(new FileReader(file));

while (in.ready()) {

String s = in.readLine();

//1% chance to trigger, if it is never triggered by chance you will display the last line
if (((int)(Math.random*100)) == 50)
break;

}
in.close();
System.out.println(s);

Alternatively a solution like this might be more elegant and gives you an evenly distributed chance of getting either of the values:

BufferedReader in = new BufferedReader(new FileReader(file));
List<String> myNicknames = new ArrayList<String>();
String line;

while ( (line = in.readLine()) != null) {
myNicknames.add(line);
}
in.close();

System.out.println(myNicknames.get( (int)(Math.random() * myNicknames.size()) ));

How to select a random line from a .txt file in Kotlin

As mentioned in the comments, use readLines() in combination with random():

File("file.txt").readLines().random()

But, as the documentation of readLines() says:

Do not use this function for huge files.

How to display random line from text file

The basic idea is to get a random index from 0 to the number of lines and then use it to retrieve this line.

int randomLineNumber = random.nextInt(numberOfLines);


Related Topics



Leave a reply



Submit