How can I recursively print a File Array? - java

I would like to know how to recursively print a File[]. I have made a program but it seems that the program is going out of bounds and I don't know how to fix it. Can someone please give me a few pointers or hints on how to solve this problem? Thanks.
import java.io.*;
public class RecursiveDir {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
public static void main(String[]args) throws IOException {
System.out.print("Please enter a directory name: ");
File f = new File(br.readLine());
FileFilter filter = new FileFilter() {
public boolean accept(File f) {
if(f.isDirectory()) {
return true;
}
return false;
}
};
File[] list = f.listFiles(filter);
System.out.println(returnDir(list,list.length));
}
public static File returnDir(File[] file,int counter) {
File f = file[counter];
if(counter == 0) {
return file[0];
}else {
return f = returnDir(file,counter--);
}
}
}
EDIT: I followed the comments below and changed return f = returnDir(file,counter--); to
return f = returnDir(file,--counter); and also changed returnDir(list,list.length); to
returnDir(list,list.length-1);, my code runs fine but now nothing is printing.

You are going out of the array bound because you need to pass list.length - 1 to the method.
Even if you did that, though, you would have an infinite recursion, because counter-- will use the value of counter, and then decrement it. So that means you are calling returnDir with the current value of counter. Use either --counter, or counter - 1.

What do expect to happen here? You don't seem to be doing anything with the files as you visit them. There is no need for recursion to loop through the files in the directory, the recursion is needed when you hit a file in the list that is a directory.

You are indeed going out of bounds. You need to change
returnDir(list,list.length);
to
returnDir(list,list.length - 1 );

You seem to be missing your System.out.println() calls. You are looping through the files and not doing anything with them.

Your initial call to returnDir should be
returnDir(list,list.length-1);
Paul

Related

Is there any better file search algorithm than recursion?

I have used recursion to search for particular type of file (for example .pdf files is used here).
My recursion algorithm searches for all subfolder.
However I found that it lacks performance when there is too many sub-folder. sub-sub-folder, sub-sub-sub-folder.
I want to know if there is better algorithm for file searching.
Below is my recursion code for file searching. I have used .pdf file as an example
import java.io.File;
public class FInd {
public static void main(String[] args) {
File f = new File("D:/");
find(f);
}
public static void find(File f){
File []list = f.listFiles();
try{
for(int i=0;i<list.length && list.length>0;i++){
if(list[i].isFile() && (list[i].getName().contains(".pdf")) ||
list[i].getName().contains(".PDF"))
System.out.println(list[i].getAbsolutePath());
if(list[i].isDirectory()) find(list[i]);
}
}catch(Exception e){
}
}
}
This code is somewhat faster or equal to when compared to search option in file explorer. I want to know any faster algorithm than this
try the iterative way
public class Find {
public static void main(String[] args) {
File f = new File("D:/");
Stack stack = new Stack<File>();
stack.push(f);
while (!stack.empty())
{
f = (File) stack.pop();
File []list = f.listFiles();
try{
for(int i=0;i<list.length && list.length>0;i++){
if(list[i].isFile() && (list[i].getName().contains(".pdf")) ||
list[i].getName().contains(".PDF"))
System.out.println(list[i].getAbsolutePath());
if(list[i].isDirectory()) stack.push(list[i]);
}
}catch(Exception e){
}
}
the problem with threading is that launching them has a cost, so the increase in file browsing + recursion has to be better than the additional cost of N folders/threads.
This is a simple method that uses a loop (the classical replacement for recursion)
static boolean avoidRecursion(String target){
File currentDir = new File(System.getProperty("user.home"));
Stack<File> dirs = new Stack<File>();
dirs.push(currentDir);
do{
for(File f : dirs.pop().listFiles()){
if (f.isDirectory())
dirs.push(f);
else{
if (f.getName().equals(target))
return true;
}
}
}while(!dirs.isEmpty());
return false;
}
Measure both approaches and choose the option that is faster
Probaply you could use multithreading...
Each folder you enter, you start at new thread... Even if you have more threads than your CPU, it ist not a Problem since Windows Can run much more threads...
Use the Files.walk() method which returns a Java8 Stream. You can parallelize that calculation quite easily by using a parallel stream.
Use the following convenient idiom in a try with resources method:
try(Stream vals = Files.walk(rootPath)){
.... }
In the rootPath, you could use Paths.get("root location") to actually get to the root location.

Smoother way to exit a void recursive Java function

So I wrote this function that behaves like Knuth's Algorithm X. Just for illustration - the function requires a large matrix of possible rows among which it tries to select the combination of the ones that make up for a legitimate solution.
The thing is, once we found the solution, since its void, the function doesn't return anything and instead just backtracks up (which consequently means it prints out sudoku for every level in the recursion depth).
Any suggestions on how to end the function the moment the solution is found? I am currently using System.exit(0) but that isn't nice since the program then ends the moment you find the solution (so anything you want to do afterwards is impossible - for example run the function on array of sudokus and solve each one).
The code is here:
public static void solve(ArrayList<int[]> solution, ArrayList<int[]> coverMatrix) {
if (Arrays.equals(solvedCase, workCase)) {
//this means we found the solution
drawSudoku(testOutput);
System.exit(0);
} else {
//find the column we didnt yet cover
int nextColToCover = findSMARTUnsatisfiedConstraint(coverMatrix, workCase);
//get all the rows that MIGHT solve this problem
ArrayList<int[]> rows = matchingRows(coverMatrix, nextColToCover);
//recusively try going down every one of them
for (int i = 0; i < rows.size(); i++) {
//we try this row as solution
solution.add(rows.get(i));
//we remove other rows that cover same columns (and create backups as well)
removeOtherRowsAndAdjustSolutionSet(coverMatrix);
if (isSolutionPossible(coverMatrix)) {
solve(solution, coverMatrix);
}
// here the backtracking occurs if algorithm can't proceed
// if we the solution exists, do not rebuild the data structure
if (!Arrays.equals(solvedCase, workCase)) {
restoreTheCoverMatrix(coverMatrix);
}
}
}
}
If I understand you correctly, you want to end recursion when you got the first solution. You can achieve this by having boolean return type for the method, and return true when you get first solution :.
public static boolean solve(ArrayList<int[]> solution, ArrayList<int[]> coverMatrix) {
if (Arrays.equals(solvedCase, workCase)) {
//this means we found the solution
drawSudoku(testOutput);
return true;
} else {
//find the column we didnt yet cover
int nextColToCover = findSMARTUnsatisfiedConstraint(coverMatrix, workCase);
//get all the rows that MIGHT solve this problem
ArrayList<int[]> rows = matchingRows(coverMatrix, nextColToCover);
//recusively try going down every one of them
for (int i = 0; i < rows.size(); i++) {
//we try this row as solution
solution.add(rows.get(i));
//we remove other rows that cover same columns (and create backups as well)
removeOtherRowsAndAdjustSolutionSet(coverMatrix);
if (isSolutionPossible(coverMatrix)) {
boolean result = solve(solution, coverMatrix);
if(result == true) return result;//else continue
}
// here the backtracking occurs if algorithm can't proceed
// if we the solution exists, do not rebuild the data structure
if (!Arrays.equals(solvedCase, workCase)) {
restoreTheCoverMatrix(coverMatrix);
}
}
return false;
}
}
You can use the AtomicReference Class with a Boolean:
public static void solve(ArrayList<int[]> solution, ArrayList<int[]> coverMatrix, AtomicReference<Boolean> test) {
if (Arrays.equals(solvedCase, workCase)) {
//this means we found the solution
drawSudoku(testOutput);
test.set(true);//System.exit(0);
}
solve(solution, coverMatrix, test);
if(!test.get())
{
// here the backtracking occurs if algorithm can't proceed
// if we the solution exists, do not rebuild the data structure
if (!Arrays.equals(solvedCase, workCase)) {
restoreTheCoverMatrix(coverMatrix);
}
}
You can call your method like this(just initialize the Boolean to false):
public static void main(String[] args)
{
AtomicReference<Boolean> test1 = new AtomicReference<Boolean>();
test1.set(false);
solve(***, ***, test1);
}
You could misuse the concept of exceptions for that, although I would not recommend it.
First define a custom exception class.
public class SuccessException extends Exception {}
Throw an instance on success.
if (Arrays.equals(solvedCase, workCase)) {
drawSudoku(testOutput);
throw new SuccessException();
}
Call the function initially in a try block.
try {
solve(solution, coverMatrix);
} catch(SuccessException e) {
/* Solution found! */
}

Variable Scope - JAVA Class/Method

I am reading in data from a text file into an ArrayList and then trying to search for a particular string in that ArrayList (the second method).
I believe that I am correctly reading in the data however am struggling to write methods to implement on the ArrayList once it has been filled. For instance, in the checking method below, it is returning a false when I am certain the input String is in the data structure.
I recognize this is likely a problem with my variable scope or how my methods are interacting with each other (i.e, the arraylist is not actually filled with the data when I am checking it).
Any help would be much appreciated - thanks
import java.util.*;
import java.io.*;
public class Word {
ArrayList<String> diclist = new ArrayList<String>();
private void readIn() throws FileNotFoundException {
File file = new File("filepath");
Scanner s = new Scanner(file);
s.useDelimiter("\n");
while (s.hasNextLine()) {
diclist.add(s.nextLine());
}
s.close();
}
public boolean checkIn(String z) {//Check if input string z is in diclist
for (int i = 0; i < diclist.size(); i++) {
if (diclist.get(i).equals(z)) {return true;}
}
return false;
}
}
There are no obvious problems in the code you posted so far. After calling readIn, if the file exists, readable and not empty, the list should get populated. I suggest running it through a debugger.
Note that the checkIn method can be vastly simplified to this:
return diclist.contains(z);

Merge sort java.lang.StackOverflowError

I am working on a project for school and things are going well until i tried to perform a merge sort on my ArrayList.
It will run but then it errors out. The first error of many is Exception in thread "main" java.lang.StackOverflowError.
I have looked over the code and cant find out why the error is occurring.
It does give me a location ( line 74:first_half = mergeSort(first_half); ) but i don't see the issue.
public static void main(String[] args) throws IOException {
// URL url = new
// URL("https://www.cs.uoregon.edu/Classes/15F/cis212/assignments/phonebook.txt");
FileReader fileReader = new FileReader("TestSort.txt");
BufferedReader bufferReader = new BufferedReader(fileReader);
String entry = bufferReader.readLine();
// Scanner s = new Scanner(url.openStream());
// int count = 0;
while (entry != null) {
// String person = s.nextLine();
String phoneNum = entry.substring(0, 7);
String name = entry.substring(9);
PhonebookEntry newentry = new PhonebookEntry(name, phoneNum);
phoneBook.add(newentry);
entry = bufferReader.readLine();
}
// ********************Selection
// Sort*************************************
ArrayList<PhonebookEntry> sortList = new ArrayList<PhonebookEntry>(phoneBook);
for (int min = 0; min < sortList.size(); min++) {
for (int i = min; i < sortList.size(); i++) {
int res = sortList.get(min).getName().compareTo(sortList.get(i).getName());
if (res > 0) {
PhonebookEntry temp = sortList.get(i);
sortList.set(i, sortList.get(min));
sortList.set(min, temp);
}
}
}
for (PhonebookEntry sortentry : sortList) {
System.out.println(sortentry);
}
System.out.println(mergeSort(mergeSortList));
}
// *****************************merge sort******************************************
static int mergecounter = 0;
static ArrayList<PhonebookEntry> mergeSortList = new ArrayList<PhonebookEntry>(appMain.phoneBook);
public static ArrayList<PhonebookEntry> mergeSort(ArrayList<PhonebookEntry> mergeSortLists) {
if (mergeSortLists.size() == 1) {
return mergeSortLists;
}
int firstHalf = mergeSortLists.size() % 2 == 0 ? mergeSortLists.size() / 2 : mergeSortLists.size() / 2 + 1;
ArrayList<PhonebookEntry> first_half = new ArrayList<PhonebookEntry>(mergeSortLists.subList(0, firstHalf));
ArrayList<PhonebookEntry> mergeSortHalf2 = new ArrayList<PhonebookEntry>(
mergeSortLists.subList(first_half.size(), mergeSortLists.size()));
System.out.println(++mergecounter);
first_half = mergeSort(first_half);
mergeSortHalf2 = mergeSort(mergeSortHalf2);
return merge(first_half, mergeSortHalf2);
}
public static ArrayList<PhonebookEntry> merge(ArrayList<PhonebookEntry> first_half,
ArrayList<PhonebookEntry> mergeSortHalf2) {
ArrayList<PhonebookEntry> returnMerge = new ArrayList<PhonebookEntry>();
while (first_half.size() > 0 && mergeSortHalf2.size() > 0) {
if (first_half.get(0).getName().compareTo(mergeSortHalf2.get(0).getName()) > 0) {
returnMerge.add(mergeSortHalf2.get(0));
mergeSortHalf2.remove(0);
}
else {
returnMerge.add(first_half.get(0));
first_half.remove(first_half.get(0));
}
}
while (first_half.size() > 0) {
returnMerge.add(first_half.get(0));
first_half.remove(first_half.get(0));
}
while (mergeSortHalf2.size() > 0) {
returnMerge.add(mergeSortHalf2.get(0));
mergeSortHalf2.remove(mergeSortHalf2.get(0));
}
return returnMerge;
}
}
My opinion there is no error in code.
How so sure?
I ran you code in my environment and its executed without any error.
With the text file i found at https://www.cs.uoregon.edu/Classes/15F/cis212/assignments/phonebook.txt As input
and done a simple implementation for PhonebookEntry
Then why is this error?
First off all try to understand the error, I mean why StackOverflowError occur. As there are lots of I am not going to explain this
But please read the top answer of this two thread and i am sure you will know why this happen.
Thread 1: What is a StackOverflowError?
Thread 2: What actually causes a Stack Overflow error?
If you read those I hope you understand the summury is You Ran Out Of Memory.
Then why I didnt got that error: Possible reason is
In my environment I configured the jvm to run with a higher memory 1024m to 1556m (as eclipse parameter)
Now lets analyze your case with solution:
Input: you have big input here ( 50,000 )
To check you code try to shorten the input and test.
You have executed two algorithm in a sigle method over this big Input:
When a method execute all its varibles stay in the memory untill it complete its execution.
so when you are calling merge sort all previouly user vairables and others stay in the memory which can contribute to this situation
Now if you use separated method and call them from the main method like write an method for selection sort, all its used varible will go out of scope
and possibly be free (if GC collect them) after the selection sort is over.
So write two separated method for reading input file and selection sort.
And Please Please close() those FileReader and BufferedReader.
Get out of those static mehtod . Make them non static create and object of the class and call them from main method
So its all about code optimization
And also you can just increase the memory for jvm and test by doing like this java -Xmx1556m -Xms1024m when ruining the app in command line
BTW, Thanks for asking this this question its gives me something to think about

Java class method: editing an array of strings with a for loop

To be blunt, I was creating a class called 'Directory', which handles/offers directory operations such as reading the directory data, checking to see in a name exists in the directory in a case- independent manner, adds names to the directory, deletes names from the directory, and writes the updated directory to file Directory.txt. I'm stuck upon a method I was trying to create, which is supposed to remove an element from an array, and move all the following elements down a position. Here is my complete code for this class, the method which doesn't seem to be working properly is delete():
package homeworks;
import java.util.*;
import java.io.*;
public class Directory {
// max directory size = 1024
final int maxDirectorySize = 1024;
String directory[] = new String[maxDirectorySize];
int directorySize = 0;
File directoryFile = null;
Scanner directoryDataIn = null;
//constructor
Directory(String directoryFileName) {
directoryFile = new File(directoryFileName);
try {
directoryDataIn = new Scanner(directoryFile);
}
catch (FileNotFoundException e) {
System.out.printf("File %s not found, exiting!",directoryFileName);
System.exit(0);
}
// Loading Directory
while (directoryDataIn.hasNext()){
directory[directorySize++] = directoryDataIn.nextLine();
}
}
public boolean inDirectory(String name) {
for(int i=0; i<directorySize; i++){
if(directory[i].equalsIgnoreCase(name)){
return true;
}
}
return false;
}
public boolean add(String name) {
// add to directory if directory is not full
// directory size is increased by 1
// returns true if successful; false otherwise
if(directorySize<maxDirectorySize){
directory[directorySize++] = name;
return true;
}
else{
return false;
}
}
public boolean delete(String name) {
// if name is in directory, remove it and shift
// other entries to use freed space; directory size
// is reduced by 1
// returns true if successful; false
for(int i = 0; i<directorySize;){
if(directory[i].equalsIgnoreCase(name)){
for(int c = i; c<directorySize+1; c++){
directory[c] = directory[c++];
}
for(int c =0; c<directorySize; c++)
System.out.println(directory[c]);
return true;
}
i++;
}
return false;
}
public void closeDirectory() {
directoryDataIn.close();
for(int i = 0; i < directorySize; i++){
System.out.println(directory[i]);
}
// close explicitly before writing
PrintStream directoryDataOut = null;
// now open the directory data file for writing
try {
directoryDataOut = new PrintStream(directoryFile);
}
catch (FileNotFoundException e) {
System.out.printf("File %s not found, exiting!", directoryFile);
System.exit(0);
}
// write possibly updated directory back to file
for (int i = 0; i < directorySize; i++)
directoryDataOut.println(directory[i]);
directoryDataOut.close();
}
}
Another issue I had is with the last method, closeDirectory(). I was wondering how exactly you would go about checking to see if the array was changed, to see whether you have to rewrite the the file or not. I know that using 'ArrayLists' would be simpler, but I specifically must use arrays for this project. I attempted to create an array called 'originalDirectory', which is simply a replica of the array 'directory' in the constructor. However, I couldn't figure it out (I removed it afterwards).
This following code snippet looks a bit odd.
for(int c = i; c<directorySize+1; c++){
directory[c] = directory[c++];
}
when you call directory[c] = directory[c++];, you're incrementing c. You're already doing that in your for loop, so the result is that your incrementing it twice.
I don't think that you need to be doing that.
try
directory[c] = directory[c+1];
your loop condition: c<directorySize+1 also looks like it can be troublesome. if you ever call directory[c] = directory[c+1]; when c is the maximum size of your directory array, then you'll get an index out of bounds exception. I understand that directorySize might not necessarily always be the same as directory.length, but you might want to have code to account for that.

Categories