Company logo
  • Empleos
  • Bootcamp
  • Acerca de nosotros
  • Para profesionales
    • Inicio
    • Empleos
    • Cursos y retos
    • Preguntas
    • Profesores
    • Bootcamp
  • Para empresas
    • Inicio
    • Nuestro proceso
    • Planes
    • Pruebas
    • Nómina
    • Blog
    • Calculadora

0

94
Vistas
Mapping pair of elements into one with Stream IPA

So I'm wondering what is the best solution to the following problem:

I have a list of items (a custom class) in a java collection ex

List<Item> itemList = ... item1,item2,item3 etc

Each item in the collection however has a corresponding logical pair also in the collection (so the pair's are not necessarily following each other by index in the collection)

I have a helper method like

Item calculateCorrectItem(Item item1, Item item2)

which can return the correct one of a pair based on some business logic (the details of that is not relevant)

I would like to replace an item and its pair in the collection, with the result of the method above - so that every 2 elements of a pair in the collection are replaced with the calculated one based on those two.

Some details: We can assume that every element has one and only one pair.
Each item has the pair's ID as a property, like

  public class Item {
    private String id;
    private String pairId;

    the equal method is true when the ID of two items are the same.
    ...getters,setters
  }

Also, the references in the collection which i want to filter are also existing in a global cache, where every Item can be easily retrieved from, like

globalCache.getItemById(String id)

So an actual pair reference can be easily retrieved if the ID of the pair is known.

What could be an elegant solution (maybe by utilizing the Stream IPA)? In the end, the only expectation is that the collection contains one Item of each pair, the ordering doesn't matter.

9 months ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

With streams, you would have to do this using indexed access:

List<Item> calculated =
    IntStream.range(0, itemList.size() / 2)
        .mapToObj(i -> calculateCorrectItem(itemList.get(2*i+0), itemList.get(2*i+1))
        .collect(toList());

If you want to merge items based on their IDs, you can group the items by their ID:

itemList.stream()
    .collect(groupingBy(Item::getId))  // Yields a Map<IdType, List<Item>>
    .values()  // Yields a Collection<List<Item>>, where each List<Item> contains items with the same id. 
    .stream()
    .map(is -> /* invoke calculateCorrectItem, handling 1, 2 or more items in the list */)
    .collect(...)
9 months ago · Santiago Trujillo Denunciar

0

Here's another approach that performs a mutable reduction using a map (you can use a hash map if preserving the source list's order of pair IDs is unimportant):

Collection<Item> correctItems1 = itemList.stream().collect(
    LinkedHashMap<String, Item>::new, 
    (map, item) -> map.merge(item.getPairId(), item, this::calculateCorrectItem),
    Map::putAll)
  .values();

List<Item> result = new ArrayList<>(correctItems1);
9 months ago · Santiago Trujillo Denunciar

0

I'm assuming that method calculateCorrectItem(Item item1, Item item2) will produce the same result regardless of the order of the arguments and that duplicated results has to be removed from the resulting list.

List<Item> items = ... ; // obtain the items

Map<String, Item> itemById = items.stream()
       .collect(Collectors.toMap(Item::getId, // relies on uniquness of Id
                                 Function.identity()));

// set is used to alliminate duplicates since their order is not important
Set<Item> itemSet = items.stream()
        .map(item-> pairById.containsKey(item.getPairId()) ? item : // if pair isn't present return the same item, othewise merge them
                        calculateCorrectItem(item, pairById.get(item.getPairId())))
        .collect(Collectors.toSet());

List<Item> result = new ArrayList<>(itemSet);
9 months ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos