Estou interessado em uma stream
maneira y para obter uma sub-lista a partir de uma ordenada lista de objetos. O sub-lista deve começar com um objeto que corresponde uma dada condição relativa a um dos seus atributos e deve terminar com um objeto que corresponde uma condição diferente.
Vamos dizer, eu tenho a seguinte classe Element
:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Element implements Comparable<Element> {
String abbreviation;
LocalDateTime creationTime;
public Element(String abbreviation, LocalDateTime creationTime) {
this.abbreviation = abbreviation;
this.creationTime = creationTime;
}
public String getAbbreviation() {
return abbreviation;
}
public void setAbbreviation(String abbreviation) {
this.abbreviation = abbreviation;
}
public LocalDateTime getCreationTime() {
return creationTime;
}
public void setCreationTime(LocalDateTime creationTime) {
this.creationTime = creationTime;
}
@Override
public int compareTo(Element otherElement) {
return this.creationTime.compareTo(otherElement.getCreationTime());
}
@Override
public String toString() {
return "[" + abbreviation + ", "
+ creationTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + "]";
}
}
Eu recebo uma List<Element>
que é requisitada pelo creationTime
. Agora eu quero saber se existem elementos entre dois mais específicos apenas em relação à sua abbreviation
. Eu sei como filter
elementos individuais ou listas de elementos que correspondem a um determinado abbreviation
utilizando findFirst()
ou findAny()
e Collectors.toList()
. No entanto, eu só não sei como encontrar um começo sublista com uma certa abbreviation
e terminando com outra porque os elementos no meio do (e deve) não corresponder às condições e há duas condições diferentes.
Suponha que eu tenho o seguinte List<Element>
(método -generating):
private static List<Element> generateSomeElements() {
List<Element> elements = new ArrayList<Element>();
LocalDateTime now = LocalDateTime.now();
Element elementOne = new Element("ABC", now.minus(14, ChronoUnit.DAYS));
Element elementTwo = new Element("DEF", now.minus(13, ChronoUnit.DAYS));
Element elementThree = new Element("GHI", now.minus(12, ChronoUnit.DAYS));
Element elementFour = new Element("JKL", now.minus(11, ChronoUnit.DAYS));
Element elementFive = new Element("MNO", now.minus(10, ChronoUnit.DAYS));
Element elementSix = new Element("PQR", now.minus(9, ChronoUnit.DAYS));
Element elementSeven = new Element("STU", now.minus(8, ChronoUnit.DAYS));
Element elementEight = new Element("VWX", now.minus(7, ChronoUnit.DAYS));
Element elementNine = new Element("YZ1", now.minus(6, ChronoUnit.DAYS));
Element elementTen = new Element("234", now.minus(5, ChronoUnit.DAYS));
elements.add(elementOne);
elements.add(elementTwo);
elements.add(elementThree);
elements.add(elementFour);
elements.add(elementFive);
elements.add(elementSix);
elements.add(elementSeven);
elements.add(elementEight);
elements.add(elementNine);
elements.add(elementTen);
return elements;
}
Eu preciso da sublista a partir de (incluindo) "MNO"
a (inclusive) "YZ1"
manter a ordem tem na lista de origens, deixando o creationTime
lado .
Eu sei como fazer isso sem o uso de correntes (como encontrar índices de início e fim e, em seguida, obter os elementos do índice start
para o índice end
), que pode ser suficiente, mas é de algum modo antiquado e não realmente satisfazer minha ambição para a utilização de APIs modernos.
Eu poderia adicionar as maneiras que eu fiz-lhe o trabalho, mas eles seria apenas uma outra forma de descrever o problema que eu não sou capaz de resolver usando um único fluxo-statement. Além disso, essas formas são explicados em uma infinidade de diferentes questões que pedem uma possibilidade geral e não visando API fluxo.
Em geral:
Existem duas condições eList<Element>
onde uma sub-lista deve ser recolhido cujo primeiro elemento é a condição de um correspondente 1 e cujo último elemento que a condição de um correspondente 2, enquanto todos os elementos entre os que são coletados, também, e as estadias de ordem como que está na origem.
Então, se você sabe que a possibilidade de obter a sub-lista desejada com uma única instrução fluxo de API, por favor, adicioná-lo como uma resposta.
Vou ter um olhar para o reduce()
método, entretanto, talvez essa é a resposta para o mistério ...
EDIT
Eu encontrei uma solução que me dá o resultado desejado usando stream()
chamadas, mas eu preciso de três deles. Uma busca que o elemento que coincide com a primeira condição, uma segunda que se encontra o elemento correspondente para a segunda condição e, em seguida, uma que vai buscar a sublista desejada usando as creationTime
s dos dois elementos que foram encontrados nas duas primeiras stream()
s:
public static void main(String[] args) {
List<Element> elements = generateSomeElements();
// print origin once followed by a horizontal separator for the human eye
elements.forEach(element -> System.out.println(element.toString()));
System.out.println("————————————————————————————————");
// find the reference object which should be the first element of the desired
// sublist
Element fromIncluding = elements.stream()
.filter(element -> element.getAbbreviation().equals("MNO")).findFirst()
.get();
Element toIncluding = elements.stream()
.filter(element -> element.getAbbreviation().equals("YZ1")).findFirst()
.get();
List<Element> mnoToYz1 = elements.stream()
.filter(element ->
(element.getCreationTime().isAfter(fromIncluding.getCreationTime())
&& element.getCreationTime().isBefore(toIncluding.getCreationTime()))
|| element.getCreationTime().isEqual(fromIncluding.getCreationTime())
|| element.getCreationTime().isEqual(toIncluding.getCreationTime()))
.collect(Collectors.toList());
mnoToYz1.forEach(element -> System.out.println(element.toString()));
}
Se a lista de entrada é ordenada, uma outra maneira de obter o subList
estaria usando o intervalo em vez da comparação de objetos no seu exemplo como:
int fromIncluding = IntStream.range(0, elements.size())
.filter(i -> elements.get(i).getAbbreviation().equals("MNO"))
.findFirst().orElse(0);
int toIncluding = IntStream.range(fromIncluding, elements.size())
.filter(i -> elements.get(i).getAbbreviation().equals("YZ1"))
.findFirst().orElse(elements.size() - 1);
List<Element> mnoToYz1 = elements.subList(fromIncluding, toIncluding+1);