I have a list of triples
List<Triple<String, String, String>> triplets;
I want to group into a map like this
Map<Pair<String, String>, String> mapping;
Where value
of the map is the third element of the triple. And in case of the same key
it should override the remaining third value.
For example
def triples = [ {a, b, c} ; {a, d, e} ; {a, b, f } ]
// grouping
def map = [ {a,b} : c ; {a, d} : e ]
How to do that using Java 8
and its grouping
in streams?
This should do the trick:
Map<Pair<String, String>, String> result = triplets.stream()
.collect(
Collectors.toMap(
t -> new Pair(t.getOne(), t.getTwo()),
Triple::getThree,
(v1, v2) -> v2
)
);
Example of a partial pair class:
public class Pair<T, U> {
//...
@Override
public int hashCode() {
return one.hashCode() + two.hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Pair))
return false;
Pair p = (Pair) obj;
return p.one.equals(one) && p.two.equals(two);
}
}
The HashMap
class uses equals
method to identify key objects uniquely. So you first need to override equals
and hashcode
methods to show the logical equality of the Pair
objects for the Map
class.
Then come back to the streams and lambda. For each triplet use Collectors.toMap
with the Pair
object as the key and the other remaining value of the Triplet
as the value. Then provide a mergeFunction
to handle key conflicts. In your case, you need to keep the previous value while discarding new value. That's all you need to do.
Update
I have updated the merge function as per the below comments.
If you want to use Collectors.groupingBy
, you can combine it with downstream mapping
and reducing
Collectors
:
@Data @AllArgsConstructor
class Triple {
String x, y ,z;
}
@Data @AllArgsConstructor
class Pair {
String x, y;
}
List<Triple> lst = List.of(new Triple("a", "b", "c"),
new Triple("a", "d", "e"),
new Triple("a", "b", "f"));
Map<Pair, String> map = lst.stream()
.collect(Collectors.groupingBy(t -> new Pair(t.x, t.y),
Collectors.mapping(t -> t.z,
Collectors.reducing(null, (x,y) -> y))));
// {Pair(x=a, y=b)=f, Pair(x=a, y=d)=e}
You could also change (x,y) -> y
to (x,y) -> x
to keep the first occurrance instead.
here ici a possible solution
String[] l1=new String[]{"a", "b", "c"};
String[] l2={"a", "d", "e"};
String[] l3={"a", "b", "c"};
List<String[]> t=new ArrayList<>();
t.add(l1);
t.add(l2);
t.add(l3);
Map<String[],String> m=t.stream().
collect(Collectors.toMap(x->new String[]{x[0],x[1]}, x->x[2],(x,y)->x));
but It depends on the type of Triple if it override equals there will be no duplication otherwise it will be duplication in the key of the map
Using Map::merge :
Map<Pair<String, String>, String> result = new HashMap<>();
triplets.forEach(e -> result.merge(new Pair<>(e.getOne(), e.getThree()), e.getThree(), (o, n) -> o));
This inserts the elements of the triplets
list into a map where the keys are a pair representing the first and second value of the Triple
and the values of the map are the third value of the Triple
.
In the case of a key collision, we use the remapping function (o, n) -> o
to maintain the old ( o
) value.
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.