1

It's my second time asking here and straight to the point. I can't seem to find a solution and I know it's not impossible. I wrote a java program that can generate a set of combination of any length, when I stop the program I don't want to start from the beginning how can I pick up from where I stopped? Thanks.

Example (for length 3):

If I start from aaa ==> 9zI and I stop the program here, I don't want to start from aaa all over but start from 9zI and continue to 999. I just want to continue from where I left off.

public class Main {

public static void main(String[] args) {
    S_Permutation sp = new S_Permutation();
    String text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    FileClass.fileExist("new.txt", true);
    System.out.println("");

    sp.permutation(text, "", 7, "sha256.txt","Kaaaaaa");
  }
}  

=====================================================================

public class S_Permutation {

private List<String> permutation;

public S_Permutation() {
    permutation = new ArrayList<>();
}

public boolean saveThis(String words, char a, int limit) {
    int count = 0;
    limit++;
    for (char character : words.toCharArray()) {
        if (count == limit) {
            return false;
        }

        if (character == a) {
            count++;
        } else {
            count = 0;
        }
    }

    return count < limit;
}
private int counter = 0;
private boolean seen = false;
public void permutation(String str, String prefix, int lengthOfPermutationString, String filename, String startPoint) {
    if (prefix.equalsIgnoreCase(startPoint))
    {
        seen = true;
    }
    if (counter == 0) {
        if (startPoint.length() != lengthOfPermutationString) {
            for (int i = startPoint.length(); i < lengthOfPermutationString; i++) {
                startPoint += str.charAt(0);
            }
        }
        counter = -45;
    }
    if (prefix.length() == lengthOfPermutationString) {
        boolean savethis = true;

        for (int i = 0; i < prefix.length(); i++) {
            savethis = this.saveThis(prefix, prefix.charAt(i), 13);
            if (!savethis) {
                break;
            }
        }
        if (savethis && seen) {
            System.out.println(prefix);
            //permutation.add(prefix);
        }

    } else {
        for (int i = 0; i < str.length(); i++) {
            if (permutation.size() == 1000) {
                FileClass.WriteFile("new.txt", permutation);
                permutation.clear();
            }

            permutation(str, prefix + str.charAt(i), lengthOfPermutationString, filename, startPoint);
        }
        FileClass.WriteFile("new.txt", permutation);
        permutation.clear();

      }
  }
 }

=========================================================================

public class FileClass {

public static boolean WriteFile(String filename, List<String> doc) {

    try {
        if (!filename.contains(".txt")) {
            filename += ".txt";
        }

        RandomAccessFile raf = new RandomAccessFile(filename, "rw");
        String writer = "";

        writer = doc.stream().map((string) -> string + "\n").reduce(writer, String::concat);
        raf.seek(raf.length());
        raf.writeBytes(writer);
        raf.close();
    } catch (Exception e) {
        System.out.println(e.getMessage());
        System.out.println("Error");
        new Scanner(System.in).nextLine();

        return false;
    }

    return true;
}
static RandomAccessFile raf;
public static boolean fileExist(String filename, boolean delete){
    File file = new File(filename);
    if (file.exists() && delete)
    {
        return file.delete();
    }
    return file.exists();
}
public static void WriteFile(String filename, String text) {

    try {
        if (!filename.contains(".txt")) {
            filename += ".txt";
        }

        raf = new RandomAccessFile(filename, "rw");
        long length = raf.length();
        raf.setLength(length + 1);
        raf.seek(raf.length());
        raf.writeBytes(text + "\n");

    } catch (Exception e) {
    }

}

private static void write(List<String> records, Writer writer) throws IOException {
    for (String record : records) {
        writer.write(record);
    }
    writer.flush();
    writer.close();

}

public static void stringWriter(List<String> records, String filename) {

    try {
        File file = new File(filename);
        FileWriter writer = new FileWriter(file, true);
        write(records, writer);
    } catch (Exception ex) {
        System.out.println(ex.getMessage());
        new Scanner(System.in).nextLine();
    }
}

public static boolean CloseFile() {
    try {
        raf.close();
        return true;
    } catch (Exception e) {
        return false;
    }
  }
 }
Nikolai
  • 760
  • 4
  • 9
  • 2
    write to a file and read from it, but you have to do it on every permutation since the red stop button in eclipse or wherever is a hard stop, meaning there is no shutdown hook executed --> you can't execute code on that shutdown – XtremeBaumer Aug 29 '17 at 07:07
  • I'm not clear @XtremeBaumer I need to know how I can continue. Saving to file and reading from it will continue from where I left off how? –  Aug 29 '17 at 07:17
  • You just need to read last line, test wich permutation has in, and continue generating them. – Shirkam Aug 29 '17 at 07:23
  • @PenDiv what you will do is to write every permutation you generate into a file, so that you are always up to date once you kill the program (you can append or override). then on startup you check if the file you wrote to exists and if yes you read the last value (the how depends on how you wrote to the file). now you call your permutation method with the default values and i think its the `startPoint` you have to change to the last value from the file. and thats it – XtremeBaumer Aug 29 '17 at 07:42
  • Possible duplicate of [How can I save the state of my program and then load it?](https://stackoverflow.com/questions/19556932/how-can-i-save-the-state-of-my-program-and-then-load-it) – Tom Aug 30 '17 at 19:35

2 Answers2

0

In order to add a "Resume" mechanism, you need to make your program idempotent. One way to do it, is instead of saving the permutations - save to file the parameters that are sent to permutation on each iteration:

now each time that the program starts, it will check what were the last parameters that permutation was called with (the last line in the file), and start from there (when the program starts on the first time, nothing will be written in the file - so it will start from the beginning).

After that the recursion finished, we can call another method that will go over the lines of the file, and read only the permutations (ignoring the other parameters) and write them into a cleaner "final_result.txt" file.

Needless to say that this implementation is more costly (all the additional reads and write from disc) but that's the tradeoff for having it support "resume" operation.

Nir Alfasi
  • 53,191
  • 11
  • 86
  • 129
  • Wouldn't be easier just writing generated permutations, and continue after last write? – Shirkam Aug 29 '17 at 07:24
  • @Shirkam and how do you "continue" without knowing which arguments you should send to `permutation()` ? ;) – Nir Alfasi Aug 29 '17 at 07:29
  • In fact, you will only need to know `String str` and, maybe, `String filename. All other parameters can be known by reading last generation. So you can just write at the begining of the file those two params, and let the program "do everything else". Maybe I'm a bit confused here (and sleepy too, it's early in the morning here), but I think that could do the work. – Shirkam Aug 29 '17 at 07:36
  • @Shirkam and how do you write these two parameters as the beginning of the file upon every iteration, replacing the previous ones and maintaining the rest of the context untouched ? not saying it's not doable, just that it's more complicate ;) – Nir Alfasi Aug 29 '17 at 07:38
  • And why would you need to do that every iteration? It's very probable that `str` and `filename` aren't changing in all generation. – Shirkam Aug 29 '17 at 07:47
  • @Shirkam of course we don't have to write the filename over and over again. The OP should write only the parameters that *change* between different iterations, or even better - not pass them at all: set them to a `final` field in the constructor and re-use them. – Nir Alfasi Aug 29 '17 at 07:57
  • I think so, maybe @PenDiv could give us some indication about which parameters are inmutable, so answers can be improved? – Shirkam Aug 29 '17 at 08:02
  • Most of the parameters are immutable except the starting point which will always change according to the desired string length. –  Aug 29 '17 at 08:20
  • @Shirkam you're diverting the discussion, which parameters are immutable is not the point. The point is, that in order to make your program resumable you need to make it idempotent. And the principle of *how* to make it idempotent is the heart of this answer. Implementation details I'll leave to the OP. – Nir Alfasi Aug 29 '17 at 16:20
  • Great answer @alfasin. How can I make my program idempotent, to be honest it's sounding more complicating and I have no idea. I love a challenge please put me through. Thanks –  Aug 30 '17 at 12:44
  • @PenDiv the answer explains how to do it - if you don't understand something in it - please comment with what specifically don't you understand. – Nir Alfasi Aug 30 '17 at 12:49
0

To save/restore process in the middle of its work, you need something we can call a "state" and implement generating combinations in iterative way. In my implementation the "state" is pos object (I assume set and k will not change on "resume").

My implementation of the problem would be following:

public class RepeatComb {
    private int[] pos;
    private String set;
    public RepeatComb(String set, int k) {
        this.set = set;
        pos = new int[k];
    }
    public int[] getState() {return Arrays.copyOf(pos, pos.length);}
    public void resume(int[] a) {pos = Arrays.copyOf(a,a.length);}
    public boolean next() {
        int i = pos.length-1;
        for (int maxpos = set.length()-1; pos[i] >= maxpos; ) {
            if (i==0) return false;
            --i;
        }
        ++pos[i];
        while (++i < pos.length) pos[i]=0;
        return true;
    }
    public String getCur() {
        StringBuilder s = new StringBuilder(pos.length);
        for (int i=0; i < pos.length; ++i)
            s.append(set.charAt(pos[i]));
        return s.toString();
    }

    public static void main(String[] args) {
        int[] state;
        String text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        RepeatComb comb = new RepeatComb(text, 3);
        int stop = 10; //break after 10
        do {
            if (stop-- == 0) break;
            System.out.println(comb.getCur());
        } while (comb.next());
        //save state
        state = comb.getState();
        System.out.println("---------");

        //resume (with the same args: text,3)
        stop = 10; //break after 10
        comb = new RepeatComb(text, 3);
        comb.resume(state); // resume here
        do {
            if (stop-- == 0) break;
            System.out.println(comb.getCur());
        } while (comb.next());
    }
}

Update: I've added functions for getting state and resuming from it and example of use. state array can be saved in file, then restored.

krzydyn
  • 1,012
  • 9
  • 19