I've just started looking at Java 8 and trying out lambdas, below is the problem i wanted to solve
Below is the code so far I have
Map<String, List<List<DataType>>> a = Arrays.stream(OperatorType.values())
.collect(
groupingBy(i -> i.getKey(),
mapping(i -> i.getSupportedtypes(),
Collectors.toList())));
The above snippet works, but thats not what i want. I want to it to be returning Map<String, List<DataType>>
I am guessing some way of flat mapping will resolve the question
OperatorType enum for reference
public enum OperatorType {
IS_ONE_OF("IS_ONE_OF", 1,
Collections.singletonList(DataType.ALL)),
IS_NOT_ONE_OF("IS_NOT_ONE_OF", 2,
Collections.singletonList(DataType.ALL)),
ENDS_WITH("ENDS_WITH", 3,
Collections.singletonList(DataType.STRING)),
DOES_NOT_ENDS_WITH("DOES_NOT_ENDS_WITH", 4,
Collections.singletonList(DataType.STRING)),
STARTS_WITH("STARTS_WITH", 5,
Collections.singletonList(DataType.STRING)),
DOES_NOT_START_WITH("DOES_NOT_START_WITH", 6,
Collections.singletonList(DataType.STRING)),
MATCHES("MATCHES", 7,
Collections.singletonList(DataType.STRING)),
DOES_NOT_MATCH("DOES_NOT_MATCH", 8,
Collections.singletonList(DataType.STRING)),
CONTAINS("CONTAINS", 9,
Collections.singletonList(DataType.STRING)),
DOES_NOT_CONTAIN("DOES_NOT_CONTAIN", 10,
Collections.singletonList(DataType.STRING)),
GREATER_THAN("GREATER_THAN", 11, Arrays.asList(DataType.INTEGER,DataType.DOUBLE)),
GREATER_THAN_OR_EQUAL_TO("GREATER_THAN_OR_EQUAL_TO", 12, Arrays.asList(DataType.INTEGER,DataType.DOUBLE)),
LESS_THAN("LESS_THAN", 13, Arrays.asList(DataType.INTEGER,DataType.DOUBLE)),
LESS_THAN_OR_EQUAL_TO("LESS_THAN_OR_EQUAL_TO", 15, Arrays.asList(DataType.INTEGER,DataType.DOUBLE)),
AFTER("AFTER", 15,
Collections.singletonList(DataType.DATE)),
BEFORE("BEFORE", 16,
Collections.singletonList(DataType.DATE));
private final int value;
private final String key;
private final List<DataType> supportedtypes;
OperatorType(String key, int value, List<DataType> supportedtypes) {
this.value = value;
this.key = key;
this.supportedtypes = supportedtypes;
}
public int getValue() {
return this.value;
}
public String getKey() {
return this.key;
}
public List<DataType> getSupportedtypes() {
return this.supportedtypes;
}
@Override
public String toString() {
return String.valueOf(this.value);
}
@JsonCreator
public static OperatorType create(String key) {
if (key == null) {
throw new IllegalArgumentException();
}
for (OperatorType v : values()) {
if (v.getKey().equalsIgnoreCase(key)) {
return v;
}
}
throw new IllegalArgumentException();
}
public static OperatorType fromValue(Integer value) {
for (OperatorType type : OperatorType.values()) {
if (value == type.getValue()) {
return type;
}
}
throw new IllegalArgumentException("Invalid enum type supplied");
}
public static OperatorType fromValue(String key) {
for (OperatorType type : OperatorType.values()) {
if (type.getKey().equalsIgnoreCase(key)) {
return type;
}
}
throw new IllegalArgumentException("Invalid enum type supplied");
}
}
Found one way to do this:
public static Map<DataType, List<OperatorType>> buildmap() {
Map<OperatorType, List<DataType>> map = new HashMap<>();
Arrays.stream(OperatorType.values()).collect(groupingBy(i -> OperatorType.fromValue(i.getKey()),
mapping(i -> i.getSupportedtypes(), Collectors.toList()))).entrySet().forEach(entry ->
{
map.put(entry.getKey(),
entry.getValue().stream().flatMap(List::stream).collect(Collectors.toList()));
});
return map.entrySet().stream().flatMap(e -> e.getValue().stream().map(v -> new SimpleEntry<>(v, e.getKey())))
.collect(
Collectors.groupingBy(Entry::getKey, Collectors.mapping(Entry::getValue, Collectors.toList())));
}
I've thrown out a few methods and switched out your DataType
with Integer
in your enum, it now looks like this:
enum OperatorType {
IS_ONE_OF("IS_ONE_OF", 1,
Collections.singletonList(1)),
IS_NOT_ONE_OF("IS_NOT_ONE_OF", 2,
Collections.singletonList(1)),
ENDS_WITH("ENDS_WITH", 3,
Collections.singletonList(2)),
DOES_NOT_ENDS_WITH("DOES_NOT_ENDS_WITH", 4,
Collections.singletonList(2)),
STARTS_WITH("STARTS_WITH", 5,
Collections.singletonList(2)),
DOES_NOT_START_WITH("DOES_NOT_START_WITH", 6,
Collections.singletonList(2)),
MATCHES("MATCHES", 7,
Collections.singletonList(2)),
DOES_NOT_MATCH("DOES_NOT_MATCH", 8,
Collections.singletonList(2)),
CONTAINS("CONTAINS", 9,
Collections.singletonList(2)),
DOES_NOT_CONTAIN("DOES_NOT_CONTAIN", 10,
Collections.singletonList(2)),
GREATER_THAN("GREATER_THAN", 11, Arrays.asList(3,4)),
GREATER_THAN_OR_EQUAL_TO("GREATER_THAN_OR_EQUAL_TO", 12, Arrays.asList(3,4)),
LESS_THAN("LESS_THAN", 13, Arrays.asList(3,4)),
LESS_THAN_OR_EQUAL_TO("LESS_THAN_OR_EQUAL_TO", 15, Arrays.asList(3,4)),
AFTER("AFTER", 15,
Collections.singletonList(5)),
BEFORE("BEFORE", 16,
Collections.singletonList(5));
private final int value;
private final String key;
private final List<Integer> supportedtypes;
OperatorType(String key, int value, List<Integer> supportedtypes) {
this.value = value;
this.key = key;
this.supportedtypes = supportedtypes;
}
public int getValue() {
return this.value;
}
public String getKey() {
return this.key;
}
public List<Integer> getSupportedtypes() {
return this.supportedtypes;
}
@Override
public String toString() {
return String.valueOf(this.value);
}
}
Should be fairly straightforward to switch your DataType
back into the following code:
Map<String,List<Integer>> map = Arrays.stream(OperatorType.values()).collect(Collectors.toMap(OperatorType::getKey, OperatorType::getSupportedtypes));
map.forEach((k,v) -> System.out.println(k + " " + v));
System.out.println("");
Map<Integer,List<OperatorType>> map2 =
map.entrySet().stream()
.flatMap(e -> e.getValue().stream().map(f -> new AbstractMap.SimpleEntry<>(f,e.getKey())))
.collect(Collectors.groupingBy(r -> r.getKey(), Collectors.mapping(s -> Enum.valueOf(OperatorType.class, s.getValue()), Collectors.toList())));
map2.forEach((k,v) -> System.out.println(k + " " + v));
You can chain these two steps. But for readibility, I've left them separate.
For me the print statements print the following:
DOES_NOT_CONTAIN [2]
STARTS_WITH [2]
LESS_THAN_OR_EQUAL_TO [3, 4]
DOES_NOT_MATCH [2]
AFTER [5]
DOES_NOT_ENDS_WITH [2]
IS_ONE_OF [1]
LESS_THAN [3, 4]
GREATER_THAN_OR_EQUAL_TO [3, 4]
CONTAINS [2]
DOES_NOT_START_WITH [2]
IS_NOT_ONE_OF [1]
BEFORE [5]
GREATER_THAN [3, 4]
ENDS_WITH [2]
MATCHES [2]
1 [2, 1]
2 [7, 3, 6, 9, 4, 8, 5, 10]
3 [11, 12, 13, 15]
4 [11, 12, 13, 15]
5 [16, 15]
I know this answer is lacking some explanation, but it produces the Map<DataType,List<OperatorType>>
that you want
It looks like your keys are identical to the enum name. If that's the case:
a) You don't need the key at all; just use the enum constant's name:
public String getKey() {
return this.name();
}
b) Since the keys are unique, there's no grouping necessary. Use the toMap()
collector instead:
Map<String, List<DataType>> a = Arrays.stream(OperatorType.values())
.collect(toMap(OperatorType::getKey, OperatorType::getSupportedtypes));
You should be able to use Stream#flatMap
for this:
Map<String, List<DataType>> map = new HashMap<>();
a.entrySet().forEach(entry -> {
map.put(entry.getKey(), entry.getValue().stream()
.flatMap(List::stream)
.collect(Collectors.toList()));
});
Because the List
of List
s in each value of the Map
must be condensed, we must first make a new Map
and then re-add the elements after condensing each List<List<DataType>>
One way could be to replace the collector toList
to a more appropriate one, eg reducing
:
Map<String, List<DataType>> a = Arrays.stream(OperatorType.values())
.collect(
groupingBy(i -> i.getKey(),
mapping(i1 -> i1.getSupportedtypes(),
reducing((List<DataType>) new ArrayList<DataType>(), (l,r) -> {
List<DataType> list = new ArrayList<DataType>();
list.addAll(l);
list.addAll(r);
return list;
}))));
For better readability it might be helpful to extract the binary operator function, eg (l,r) -> join(l,r)
, where join
concatenates two lists.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.