0

I have a Map <Long, List<SerialDate>>: The SerialDate has two fields: Number,String

1 -> (Number1|String1, Number2|String2)
2 -> (Number1|String1, Number2|String2)
3 -> (Number3|String3)

The code is like:

       Map<Long, List<SerialMaskData>> upcDataMap = new HashMap<>();//
        for(SerialMappingData data : serialDataList3p){
            Long upc = data.getUpcNumber();
            String mask = data.getSerialMask();
            String algorithm = data.getSerialAlgorithm();//
            SerialMaskData serialMaskData = new SerialMaskData(mask,algorithm);//

            if(!upcDataMap.containsKey(upc)){
                List<SerialMaskData> list = new ArrayList<>();//
                list.add(serialMaskData);//
                upcDataMap.put(upc, list);
            }else{
                upcDataMap.get(upc).add(serialMaskData);

            }
        }

What I want is to do a classification:

[1,2], (Number1|String1, Number2|String2), groupId1 // because they have the same value format.
[3], (Number3|String3), groupId2

I have tried to build a reverse Map<List<Number|String>, Long>, but it was a bad idea to use List as a map key. I think it can be done with stream.groupingby but not sure how to do it.

Mark PENG
  • 1
  • 1
  • Please share it as Java code, so we can reproduce it, share the initial data, and clarify the expected output, also share your tries to achieve it – azro May 18 '22 at 05:56
  • Also, please explain what do you mean by List - do you need List filled with Number or List filled with Strings, or both? – bkomo May 18 '22 at 06:00

1 Answers1

0

You have a Map<Long,List<SerialDate>>, and for the described grouping, you would like to have a Map<List<SerialDate>,List<Long>>, right?

As you already found out yourself, having an instance of List as the key for a Map is not the best idea …

But if SerialDate provides a proper implementation of Object::toString, you can get something equivalent that should be sufficient for your purpose.

Try this:

final Map<Long,List<SerialDate>> input = …
final Map<String,List<Long>> output = new HashMap<>();

for( final var entry : input.entrySet() )
{
   final var key = entry.getValue()
     .stream()
     .map( SerialDate::toString )
     .sorted()
     .collect( joining() );
  final var values = output.computeIfAbsent( key, k -> new ArrayList<Long>() );
  values.add( entry.getKey();
}

Basically, the code converts the list into a String, and uses that String as the key for the output map. The sorting is required because two lists are (assumed to be) semantically equal if they contain the same elements, independent from their order, while for Strings the order of their 'elements' is crucial for equality.

Simply calling toString() on the List instance does not work as it will not call toString() on the element.

tquadrat
  • 3,033
  • 1
  • 16
  • 29
  • Thanks for you solution, but I need to store List. After running your solution, I found that the keys of input are not grouped. it is like a reverseMap>, but the value List only have one element. – Mark PENG May 18 '22 at 07:12
  • @MarkPENG – You noticed the condition that "`SerialDate` [must provide] a proper implementation of `Object::toString`"? That means that `SerialDate::toString` has to return something like `SerialDate [number="Number1", string="String1"]`. Otherwise, yes, the `List` will always have only one single entry. – tquadrat May 18 '22 at 13:27