Search code examples
javajava-streammapping

Translate one table structure to other on Java


I have following case.

Given table:

@Getter
@Setter
@AllArgConstructor
class OldRow {

  String type;
  String name;
  int number;
}
List<OldRow> oldTable
type Name Number
7 Alex 15
8 Alex 17
9 Alex 15
7 John 33
8 John 44
9 John 54

Need to translate it to following structure using java 11+

@Getter
@Setter
@AllArgConstructor
class NewRow {

String Name;
  int type7;
  int type8;
  int type9;
}
List<NewRow> newTable
Name type7 type8 type9
Alex 15 17 15
John 33 44 54

Thank you


Solution

  • Before giving you a way to do it, I want to emphasize a few cosmetic errors I see in your code.

    • Your java variable names should start with lower-case letters, and names with capital first letters are used for Class namings.

    • You should indent your code properly so that you (and other readers) can see the code blocks better

    I couldn't find an elegant solution with fewer lines, so someone might post it in the future but this will work for you. I will first share the code, and then explain the solution below.

    @Getter
    @Setter
    @AllArgConstructor
    class OldRow {
    
        String type;
        String name;
        int number;
    }
    
    @Getter
    @Setter
    @AllArgConstructor
    class NewRow {
    
        String name;
        int type7;
        int type8;
        int type9;
    
        public void printPretty() {
            System.out.println(this.name + " " + this.type7 + " " + this.type8 + " " + this.type9);
        }
    }
    
    
    public class MainClass {
        
        public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
            Set<Object> seen = ConcurrentHashMap.newKeySet();
            return t -> seen.add(keyExtractor.apply(t));
        }
    
        public static void main(String args[]) {
            List<OldRow> oldRows = new ArrayList<>();
            
            oldRows.add(new OldRow("8","Alex",17)); 
            oldRows.add(new OldRow("7","Alex",15)); 
            oldRows.add(new OldRow("9","Alex",15)); 
            oldRows.add(new OldRow("7","John",33)); 
            oldRows.add(new OldRow("8","John",44)); 
            oldRows.add(new OldRow("9","John",54)); 
            
            Map<String,Integer> type7Map = new HashMap<>();
            Map<String,Integer> type8Map = new HashMap<>();
            Map<String,Integer> type9Map = new HashMap<>();
            
            oldRows.forEach(oldRow -> {
                if(oldRow.type.equals("7")) 
                    type7Map.put(oldRow.getName(), oldRow.getNumber());
                if(oldRow.type.equals("8")) 
                    type8Map.put(oldRow.getName(), oldRow.getNumber());
                if(oldRow.type.equals("9")) 
                    type9Map.put(oldRow.getName(), oldRow.getNumber());
            });
            
            List<NewRow> newRows = oldRows.stream()
                .filter(distinctByKey(OldRow::getName))
                .map(oldRow -> new NewRow(
                        oldRow.name,
                        type7Map.get(oldRow.getName()),
                        type8Map.get(oldRow.getName()),
                        type9Map.get(oldRow.getName())
                    ))
                .collect(Collectors.toList());
                
            for(NewRow newRow : newRows) {
                newRow.printPretty();
            }
    
        }
    } 
    

    The first part of the main is to create the OldRow instances you have in your example. Then 3 maps are created to keep type7, type8, and type9 values for each name. Since you only have these 3 types; we can use a static number of maps.

    These maps are filled by iterating over the oldRows list, then NewRow entities are filled into a new array by streaming the oldRows list and looking up type values from maps.

    Finally, the print statements, so that you can see what is the last state of the newRows array.