1

I am having difficulty making a deep copy of a HashMap. I tried the code below from How to copy HashMap (not shallow copy) in Java, but List at List.copyOf is giving me an error (Cannot resolve symbol 'List') and I'm not sure what to replace it with. If there is any other way to make a deep copy of HashMap, I would love to hear.

private HashMap<Character, ArrayList<int[]>> board;

public Vertex(HashMap<Character, ArrayList<int[]>> inputboard) {
        board = new HashMap<>();
        this.board = copy(inputboard);
}

public HashMap<Character, ArrayList<int[]>> copy (HashMap<Character, ArrayList<int[]>> original) {  
        HashMap<Character, ArrayList<int[]>> copy = original.entrySet().stream()
                .collect(Collectors.toMap(e -> e.getKey(), e -> List.copyOf(e.getValue())));
        return copy;
}

Before I used the above code, I also tried this from How to copy HashMap (not shallow copy) in Java but it did not make a deep copy

private HashMap<Character, ArrayList<int[]>> board;

public Vertex(HashMap<Character, ArrayList<int[]>> inputboard) {
        board = new HashMap<>();
        this.board = copy(inputboard);
}

public HashMap<Character, ArrayList<int[]>> copy (HashMap<Character, ArrayList<int[]>> original) {
       HashMap<Character, ArrayList<int[]>> copy = new HashMap<>();
       for (Map.Entry<Character, ArrayList<int[]>> entry : original.entrySet()) {
            copy.put(entry.getKey(), new ArrayList<>(entry.getValue()));
       }
       return copy;
}
shinhusky
  • 7
  • 1
  • 4
  • Do you want to copy the `int[]`s too? – Sweeper Apr 13 '21 at 04:02
  • Are you using something older than Java 10? Otherwise `List.copyOf` should be available, and you just need to `import java.util.List;`. – Sweeper Apr 13 '21 at 04:03
  • Yes, I want to copy `int []` s too. Not just keys. When I do `import java.util.List;`, I get an error that says Map is provided while HashMap> is really required. – shinhusky Apr 13 '21 at 04:10

1 Answers1

0

Both ways you showed doesn't copy the int[], i.e. not copying as deep as you want.

The first way actually returns a Map<Character, List<int[]>> rather than the HashMap<Character, ArrayList<int[]>> you want. I would recommend that you program to interfaces and change your method to return a Map<Character, List<int[]>> instead, then you can use streams like this:

public Map<Character, List<int[]>> copy (HashMap<Character, ArrayList<int[]>> original) {
    Map<Character, List<int[]>> copy = original.entrySet().stream()
        .collect(Collectors.toMap(
            Entry::getKey,
            e -> e.getValue().stream().map(x -> Arrays.copyOf(x, x.length)).collect(Collectors.toList())
        ));
    return copy;
}

If you really don't want to change the return type, you'd have to pass more arguments to specify the concrete types you want:

public HashMap<Character, ArrayList<int[]>> copy (HashMap<Character, ArrayList<int[]>> original) {
    HashMap<Character, ArrayList<int[]>> copy = original.entrySet().stream()
        .collect(Collectors.toMap(
            Entry::getKey,
            e -> e.getValue().stream().map(x -> Arrays.copyOf(x, x.length)).collect(Collectors.toCollection(ArrayList::new)),
            (x, y) -> x,
            HashMap::new
        ));
    return copy;
}

Otherwise, you can use the traditional for loops:

public HashMap<Character, ArrayList<int[]>> copy (HashMap<Character, ArrayList<int[]>> original) {
    HashMap<Character, ArrayList<int[]>> copy = new HashMap<>();
    for (Map.Entry<Character, ArrayList<int[]>> entry : original.entrySet()) {
        ArrayList<int[]> listCopy = new ArrayList<>();
        for (int[] array: entry.getValue()) {
            listCopy.add(Arrays.copyOf(array, array.length));
        }
        copy.put(entry.getKey(), listCopy);
    }
    return copy;
}

Notice that in all three code snippets, I have used Arrays.copyOf to copy the int[].

Sweeper
  • 213,210
  • 22
  • 193
  • 313