0

Description

I have a HashMap<ArrayLists<Integer>, <Integer>>, similar to the following ({Key=Value}):

{[1]=1, [3]=1, [1, 4, 6]=1, [0, 2, 3, 5, 6]=3, [6]=1}

I need to compare and then modify/remove elements in different ArrayLists (i.e., elements in the HashMap), until the following conditions are met:

  1. Each ArrayList element only belongs to one list, the list with the highest Value.
  2. If Value = 1 for all lists containing that element, then the ArrayList element belongs to the singleton list.
  3. If an ArrayList becomes empty, then it should be removed from the HashMap.

Thus for the example above, it should end up with the following:

{[1]=1, [4]=1, [0, 2, 3, 5, 6]=3}

I am used to work with arrays of arrays to do stuff like this. This time it would be practical to have the features of HashMap and ArrayList, but I am currently not comfortable to do more complicated modification of these data types. I have done several attempts and have had to prevent both ConcurrentModificationException and IllegalStateException, but have yet to succeed fully. I also have a feeling my implementations are getting unnecessary complex, so I would greatly appreciate to see an implementation by someone experienced with things like this.


A Note About The HashMap

The reason I use a HashMap (feel free to suggest something more appropriate) is that the Value is a count of how many times the ArrayList has been "encountered" and added to the HashMap.


Minimal Example

Minimal example of my latest non-working (IndexOutOfBoundsException) attempt. Note that the creation of the HashMap and ArrayLists is done statically here since in my real program it is done non-deterministically based on file contents.

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Test {
    public static void main(String[] args) {
        Map<List<Integer>, Integer> example = new HashMap<>(7);
        List<Integer> list = new ArrayList<>(7);
        list.add(1);
        example.put(list, 1);
        list = new ArrayList<>(7);
        list.add(3);
        example.put(list, 1);
        list = new ArrayList<>(7);
        list.add(1);
        list.add(4);
        list.add(6);
        example.put(list, 1);
        list = new ArrayList<>(7);
        list.add(0);
        list.add(2);
        list.add(3);
        list.add(5);
        list.add(6);
        example.put(list, 3);
        list = new ArrayList<>(7);
        list.add(6);
        example.put(list, 1);
        System.err.println(example);

        Map<List<Integer>, Integer> copy = new HashMap<>(example);
        for (Map.Entry<List<Integer>, Integer> outer : example.entrySet()) {
            for (Map.Entry<List<Integer>, Integer> inner : copy
                .entrySet()) {
                for (int i : outer.getKey()) {
                    int oSize = outer.getKey().size();
                    int iSize = inner.getKey().size();
                    int oValue = outer.getValue();
                    int iValue = inner.getValue();

                    if (!(inner.equals(outer)) && (inner.getKey()
                        .contains(i))) {
                        if (oSize == 1) {
                            if (oValue < iValue) {
                                outer.getKey().remove(i);
                            } else {
                                inner.getKey().remove(i);
                            }
                        } else if (iSize == 1) {
                            if (iValue < oValue) {
                                outer.getKey().remove(i);
                            } else {
                                inner.getKey().remove(i);
                            }
                        } else {
                            if (oValue < iValue) {
                                outer.getKey().remove(i);
                            } else {
                                inner.getKey().remove(i);
                            }
                        }
                    }
                }
            }
        }
    }
}
Klorax
  • 579
  • 2
  • 6
  • 10
  • Please include the relevant code in the question. – Eran Sep 22 '19 at 12:03
  • Could you explain why [3]=1 excluded from the result? – i.bondarenko Sep 22 '19 at 12:19
  • @i.bondarenko Due to 1, it should belong to the long list with `Value = 3`. – Klorax Sep 22 '19 at 12:21
  • Using a mutable value as a key will cause a HashMap to malfunction. If you modify any of those ArrayLists, you will change their hashCodes, and your HashMap will become corrupt and unreliable. You must never modify an object which is being used as a key in a HashMap. – VGR Sep 22 '19 at 16:13

2 Answers2

2

Its highly unusual to use an ArrayList as the key to a HashMap (Are mutable hashmap keys a dangerous practice?). But assuming you are okay with this, to update a Map entry you could remove the entry(both the List and the integer) from the hasmap, create a new List that has your changes, and then reinsert if necessary.

Martin'sRun
  • 522
  • 3
  • 11
  • Thanks, did not know about this. Will add a comment about why I use HashMap, feel free to suggest something more appropriate if possible. – Klorax Sep 22 '19 at 12:23
2

In my poor opinion, I suggest order the map value (according to the highest value) in 1st round, then complete our deletion work with business logic.

For example:

        Map<List<Integer>, Integer> example = new HashMap<>();
        // data initialize

        // order by Map.Entry::getValue desc
        List<Map.Entry<List<Integer>, Integer>> collect = example.entrySet()
                .stream()
                .sorted((e1, e2) -> e2.getValue() - e1.getValue())
                .collect(Collectors.toList());

        // remove duplicate list element in Map.Entry::getKey
        Set<Integer> tmp = new HashSet<>();
        // collect.forEach(c -> c.getKey().removeIf(next -> !tmp.add(next)));
        example = collect
                .stream()
                .filter(c -> {
                    c.getKey().removeIf(next -> !tmp.add(next));
                    return !c.getKey().isEmpty();
                })
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Ye Jiahao
  • 21
  • 5
  • Generates the correct answer for this case, will study it further, thank you! What are you reserved about regarding it: "In my poor opinion"? – Klorax Sep 22 '19 at 14:39
  • Maybe remove in filter is better, it can reduce the times of traversal. (already edited this post) – Ye Jiahao Sep 22 '19 at 17:40