Encuentra una secuencia sucesiva de cadena atributos en un conjunto de objetos (API por flujo)

deHaar:

Tengo que escribir un método que toma una SortedSet<MyEvent>y una List<String>. Tiene para determinar si hay una secuencia sucesiva de MyEventque representa el dado List<String>por un determinado atributo de clase.

Vamos a suponer que no era la situación siguiente (código-):

List<String> list = new ArrayList<String>()
list.add("AAA");
list.add("BBB");

y una Set<MyEvent>

SortedSet<MyEvent> events = new TreeSet<MyEvent>();

con objetos del tipo MyEventque implements Comparable<MyEvent>(comparación por LocalDateTimesolamente).
Lo dado List<String>representa una secuencia de abreviaturas y necesito encontrar la más reciente aparición de una secuencia de MyEvents cuyos atributos de clase abbreviationque los valores de la secuencia.

Esto es lo que he hecho hasta ahora:

public static void main(String[] args) {
    SortedSet<MyEvent> events = generateSomeElements();
    List<String> sequence = new ArrayList<>();
    sequence.add("AAA");
    sequence.add("BBB");

    MyEvent desired = getMostRecentLastEventOfSequence(events, sequence);

    System.out.println("Result: " + desired.toString());
}

public static MyEvent getMostRecentLastEventOfSequence(SortedSet<MyEvent> events,
                List<String> sequence) {
    // "convert" the events to a List in order to be able to access indexes
    List<MyEvent> myEvents = new ArrayList<MyEvent>();
    events.forEach(event -> myEvents.add(event));
    // provide a temporary data structure for possible results
    SortedSet<MyEvent> possibleReturnValues = new TreeSet<MyEvent>();
    // iterate the events in order to find those with a specified predecessor
    for (int i = 0; i < myEvents.size(); i++) {
        if (i > 0) {
            // consider only successive elements 
            MyEvent a = myEvents.get(i - 1);
            MyEvent b = myEvents.get(i);
            // check if there is a 
            if (a.getAbbreviation().equals(sequence.get(0)) 
                && b.getAbbreviation().equals(sequence.get(1))) {
                // if a sequence was found, add the last element to the possible results
                possibleReturnValues.add(b);
            }
        }
    }

    // check if there were possible results
    if (possibleReturnValues.size() == 0) {
        return null;
    } else {
        // if there are any, return the most recent / latest one
        return possibleReturnValues.stream().max(MyEvent::compareTo).orElse(null);
    }
}

El método está trabajando (para esta secuencia de 2 elementos, al menos).

¿Es posible hacer eso en una sola llamada usando la API de corriente (y por un tamaño desconocido de la secuencia)?

Holger:

Su tarea no es tan difícil, basta con crear una Stream, aplique una filter, y pregunte por el valor máximo. No es el obstáculo que es necesario un elemento anterior en el predicado, pero tenemos las manos en la colección de origen, que puede proporcionarla.

En la práctica, cada SortedSetes también una NavigableSetque proporciona un lowermétodo para obtener el elemento anterior, si es que existe, pero desde su requerimiento es para apoyar una SortedSetentrada, tenemos que proporcionar un retroceso para el caso teórico de un SortedSetno ser NavigableSet.

Entonces, la operación puede ser implementado como

public static MyEvent getMostRecentLastEventOfSequence(
    SortedSet<MyEvent> events, List<String> sequence) {

    String first = sequence.get(0), second = sequence.get(1);
    UnaryOperator<MyEvent> previous;
    if (events instanceof NavigableSet) {
        NavigableSet<MyEvent> navigableSet = (NavigableSet<MyEvent>) events;
        previous = navigableSet::lower;
    }
    else previous = event -> events.headSet(event).last();

    return events.stream()
        .filter(event -> event.getAbbreviation().equals(second))
        .filter(event -> {
            MyEvent p = previous.apply(event);
            return p != null && p.getAbbreviation().equals(first);
        })
        .max(Comparator.naturalOrder()).orElse(null);
}

pero podemos hacerlo mejor que eso. Puesto que ahora estamos en busca de un máximo en una ordenada de entrada, sabemos que el primer partido es suficiente cuando la iteración hacia atrás. Una vez más, es mucho más suave cuando la entrada es en realidad una NavigableSet:

public static MyEvent getMostRecentLastEventOfSequence(
    SortedSet<MyEvent> events, List<String> sequence) {

    String first = sequence.get(0), second = sequence.get(1);
    UnaryOperator<MyEvent> previous;
    Stream<MyEvent> stream;
    if (events instanceof NavigableSet) {
        NavigableSet<MyEvent> navigableSet = (NavigableSet<MyEvent>) events;
        previous = navigableSet::lower;
        stream = navigableSet.descendingSet().stream();
    }
    else {
        previous = event -> events.headSet(event).last();
        stream = Stream.iterate(events.last(), previous).limit(events.size());
    }

    return stream
        .filter(event -> event.getAbbreviation().equals(second))
        .filter(event -> {
            MyEvent p = previous.apply(event);
            return p != null && p.getAbbreviation().equals(first);
        })
        .findFirst().orElse(null);
}

Por lo que este método será buscar hacia atrás y parada en el primer partido, que ya será el elemento máximo, sin la necesidad de recorrer todos los elementos.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=187631&siteId=1
Recomendado
Clasificación