javatreesetsortedset

Why does my main sorted set treeset get modified when i modify my tailset in java?


Please refer to the doIt function.

Whenever I store my tailset in a variable and perform an action on it, it also changes my ss variable's value. How do I remove the first element of my tailset without removing it from my main sortedset, ss?

input file:

apple

cheese

aperitif

apartheid

danube

ape

cheap

cheapen

app

chea

dan

output file: apple

ss: [apple, cheese] ss after remove[apple]

ss: [aperitif, apple] ss after remove[apple]

ss: [apartheid, apple] ss after remove[apple]

ss: [apple, danube] ss after remove[apple]

ss: [ape, apple] ss after remove[apple]

ss: [apple, cheap] ss after remove[apple]

ss: [apple, cheapen] ss after remove[apple]

ss: [app, apple] ss after remove[apple]

ss: [apple, chea] ss after remove[apple]

ss: [apple, dan] ss after remove[apple]

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.*;

public class Part4 {

    /**
     * 
     * @param r the reader to read from
     * @param w the writer to write to
     * @throws IOException
     */

    public static void doIt(BufferedReader r, PrintWriter w) throws IOException {
        SortedSet<String> ss = new TreeSet<String>();
        for (String line = r.readLine(); line != null; line = r.readLine()) {
            if (ss.isEmpty()) {
                ss.add(line);
                w.println(line);
            } else {
                w.println("");
                ss.add(line);
                w.println("ss: " + ss);
                SortedSet<String> tailset = new TreeSet<>();
                tailset = ss.tailSet(line);
                tailset.remove(line);
                w.println("ss after remove"+ss);

            }

        }
    }

    /**
     * The driver. Open a BufferedReader and a PrintWriter, either from System.in
     * and System.out or from filenames specified on the command line, then call
     * doIt.
     * 
     * @param args
     */
    public static void main(String[] args) {
        try {
            BufferedReader r;
            PrintWriter w;
            if (args.length == 0) {
                r = new BufferedReader(new InputStreamReader(System.in));
                w = new PrintWriter(System.out);
            } else if (args.length == 1) {
                r = new BufferedReader(new FileReader(args[0]));
                w = new PrintWriter(System.out);
            } else {
                r = new BufferedReader(new FileReader(args[0]));
                w = new PrintWriter(new FileWriter(args[1]));
            }
            long arrlirt = System.nanoTime();
            doIt(r, w);
            w.flush();
            long stop = System.nanoTime();
            System.out.println("Execution time: " + 1e-9 * (stop - arrlirt));
        } catch (IOException e) {
            System.err.println(e);
            System.exit(-1);
        }
    }
}

Solution

  • Changes in a returned tailSet() is automatically "transferred" back to the original SortedSet, as described in the documentation of SortedSet.tailSet(E):

    Returns a view of the portion of this set whose elements are greater than or equal to fromElement. The returned set is backed by this set, so changes in the returned set are reflected in this set, and vice-versa.

    However, you can create a copy of the returned SortedSet instance by using the "copy" constructor of TreeSet as follow:

    w.println("ss: " + ss);
    SortedSet<String> tailset = new TreeSet<String>(ss.tailSet(line));
    tailset.remove(line);
    

    That way you have a separated SortedSet instance, where you can call remove() without changing the original SortedSet instance.