Groupement de par la valeur de l'objet, de comptage et de définir ensuite la clé de groupe par le maximum d'attribut de l'objet
J'ai réussi à écrire une solution à l'aide de Java 8 API de Flux que les premiers groupes, une liste d'objet de l'Itinéraire par sa valeur et compte ensuite le nombre d'objets dans chaque groupe. Elle renvoie une cartographie des Parcours -> Long. Voici le code:
Map<Route, Long> routesCounted = routes.stream()
.collect(Collectors.groupingBy(gr -> gr, Collectors.counting()));
Et la classe de la Route:
public class Route implements Comparable<Route> {
private long lastUpdated;
private Cell startCell;
private Cell endCell;
private int dropOffSize;
public Route(Cell startCell, Cell endCell, long lastUpdated) {
this.startCell = startCell;
this.endCell = endCell;
this.lastUpdated = lastUpdated;
}
public long getLastUpdated() {
return this.lastUpdated;
}
public void setLastUpdated(long lastUpdated) {
this.lastUpdated = lastUpdated;
}
public Cell getStartCell() {
return startCell;
}
public void setStartCell(Cell startCell) {
this.startCell = startCell;
}
public Cell getEndCell() {
return endCell;
}
public void setEndCell(Cell endCell) {
this.endCell = endCell;
}
public int getDropOffSize() {
return this.dropOffSize;
}
public void setDropOffSize(int dropOffSize) {
this.dropOffSize = dropOffSize;
}
@Override
/**
* Compute hash code by using Apache Commons Lang HashCodeBuilder.
*/
public int hashCode() {
return new HashCodeBuilder(43, 59)
.append(this.startCell)
.append(this.endCell)
.toHashCode();
}
@Override
/**
* Compute equals by using Apache Commons Lang EqualsBuilder.
*/
public boolean equals(Object obj) {
if (!(obj instanceof Route))
return false;
if (obj == this)
return true;
Route route = (Route) obj;
return new EqualsBuilder()
.append(this.startCell, route.startCell)
.append(this.endCell, route.endCell)
.isEquals();
}
@Override
public int compareTo(Route route) {
if (this.dropOffSize < route.dropOffSize)
return -1;
else if (this.dropOffSize > route.dropOffSize)
return 1;
else {
//if contains drop off timestamps, order by last timestamp in drop off
//the highest timestamp has preceding
if (this.lastUpdated < route.lastUpdated)
return -1;
else if (this.lastUpdated > route.lastUpdated)
return 1;
else
return 0;
}
}
}
Ce que je voudrais en outre à atteindre, qui est la clé pour chaque groupe sera celui avec le plus grand lastUpdated valeur. J'étais déjà à la recherche à cette solution mais je ne sais pas comment combiner le comptage et le regroupement en fonction de la valeur et de la Route maximale lastUpdated valeur. Voici les données d'exemple de ce que je veux réaliser:
EXEMPLE:
List<Route> routes = new ArrayList<>();
routes.add(new Route(new Cell(1, 2), new Cell(2, 1), 1200L));
routes.add(new Route(new Cell(3, 2), new Cell(2, 5), 1800L));
routes.add(new Route(new Cell(1, 2), new Cell(2, 1), 1700L));
DOIT ÊTRE CONVERTIE EN UNE:
Map<Route, Long> routesCounted = new HashMap<>();
routesCounted.put(new Route(new Cell(1, 2), new Cell(2, 1), 1700L), 2);
routesCounted.put(new Route(new Cell(3, 2), new Cell(2, 5), 1800L), 1);
Avis que la clé pour la cartographie, qui comptait 2 Voies est l'un avec le plus grand lastUpdated valeur.
- Dans l'exemple que vous utilisez
new Route
avec 3 paramètres, alors que le seul constructeur a 4 paramètres. Pourriez-vous veuillez la corriger? - Ups my bad. Il est fixé maintenant. Fondamentalement, la dropOffSize la taille n'importe pas ici, mais je ne l'ai laisser dans le code, parce que je voulais montrer à tout le remplacé les méthodes et la méthode compareTo ne faire usage de dropOffSize.
Vous devez vous connecter pour publier un commentaire.
Voici une approche. Premier groupe dans des listes, puis de traiter les listes dans les valeurs que vous voulez vraiment:
Collectors.groupingBy
Comparator.comparing
etCollectors.toMap
au lieu de simplement les noms de méthode.lst
est en effet de typeList
. J'ai juste tiré, IntelliJ et il ne se plaint pas.collectingAndThen(groupingBy(x -> x), m -> m.values()....);
Vous pouvez définir un résumé "la bibliothèque", méthode qui combine les deux collecteurs en un seul:
Après que l'opération peut ressembler à ceci:
Mise à jour: tel collector est disponible dans mon StreamEx bibliothèque:
MoreCollectors.l'appariement()
. Également similaire collecteur est mis en œuvre dans jOOL de la bibliothèque, de sorte que vous pouvez utiliserTuple.collectors
au lieu depairing
.Collectors
...@SuppressWarnings("unchecked")
apparaît dansjava.util.stream.Collectors
🙂 C'est ok pour la bibliothèque bas niveau code. Partie de l'entreprise n'a pas d'avertissements.Object[]
avec unPair
ou tuple de type permettrait de résoudre la il. Maintenant, c'est la JRE du développeur tour...Changé equals et hashcode d'être dépendant uniquement sur le début de la cellule et de la fin de la cellule.
Ma solution ressemble à ceci:
Bien sûr, la conversion en int doit être remplacé par quelque chose de plus approprié.
groupingBy
ne s'adresse pas spécifiquement garantie que cela fonctionne.En principe, il semble que ce devrait être faisable en une seule passe. L'habitude de la ride est que cela nécessite un ad-hoc tuple ou une paire, dans ce cas, avec un
Route
et un décompte. Depuis Java ne dispose pas de telles, nous nous retrouvons à l'aide d'un tableau d'Objets de longueur 2 (comme indiqué dans Tagir Valeev réponse), ouAbstractMap.SimpleImmutableEntry
, ou un hypothétiquePair<A,B>
classe.L'alternative est d'écrire un peu de valeur classe qui détient un
Route
et un décompte. Bien sûr, il y a de la douleur dans le faire, mais dans ce cas je pense que c'est payant, car il fournit un endroit pour mettre la combinaison de la logique. Qui simplifie le flux de l'opération.Voici la classe de valeur contenant un
Route
et un décompte:Assez simple, mais l'avis de l'
combine
méthode. Il combine deuxRouteCount
valeurs en choisissant l'Route
qui a été mis à jour, plus récemment, et en utilisant la somme des comtes. Maintenant que nous avons cette classe de valeur, nous pouvons écrire un one-pass flux pour obtenir le résultat que nous voulons:Comme d'autres réponses, cette partie regroupe les routes dans des classes d'équivalence fondée sur le début et la fin de la cellule. La réelle
Route
exemple utilisé en tant que la clé n'est pas significatif; c'est juste un représentant de sa classe. La valeur sera d'une seuleRouteCount
qui contient leRoute
instance qui a été mis à jour, plus récemment, avec le comte d'équivalentRoute
instances.La façon dont cela fonctionne est que chaque
Route
instance qui a le même début et de fin des cellules est ensuite introduit dans l'aval du collecteur degroupingBy
. Cettemapping
collectionneur de cartes leRoute
instance dans uneRouteCount
instance, puis le passe à unreducing
collecteur qui réduit les cas à l'aide de la combinaison de la logique décrite ci-dessus. La et de-puis la partie decollectingAndThen
extraits de la valeur de laOptional<RouteCount>
que lereducing
collecteur de produit.(Normalement un nu -
get
est dangereux, mais nous n'arrivons pas à ce collecteur à tous sauf si il y a au moins une valeur disponible. Doncget
est sûr dans ce cas.)toMap(r->r, RouteCount::fromRoute, RouteCount::combine)
au lieu de groupingBy+réduction