0

So I am trying to do this problem solving interview question where im givin an array of 6,4,7,9,3,12 and trying to return the three values that would add up to the value 13. The catch is that im only using streams to do this problem. No basic. I tried doing it with just .map and flatmap but i ended up having to use one foreach loop due to a void method i am using.

here is the code:

package com.example.demo_david;

import models.Wrapper;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);

        Integer value = 13;
        List<Integer> fixMe = new ArrayList<>(List.of(6,4,7,9,3,12));
        System.out.println("answer: " + findTheOnesThatEqualTheResult(value, fixMe));
    }

    static List<Integer> findTheOnesThatEqualTheResult(int maxValue, List<Integer> list){
        Wrapper wrapper = new Wrapper();

        List<ArrayList<Integer>> collectedList = list.stream().map(fixMeCurrentNumber ->
                computeLogic(maxValue, wrapper, fixMeCurrentNumber)).collect(Collectors.toList());

        List<Integer> flattenedList = collectedList.stream()
                .flatMap(Collection::stream)
                .collect(Collectors.toList());

        return flattenedList;
    }

    private static ArrayList<Integer> computeLogic(int maxValue, Wrapper wrapper, Integer fixMeCurrentNumber) {

        if((wrapper.getSavedNumbers() == null && fixMeCurrentNumber <= maxValue) ||
                (wrapper.getSavedNumbers().size() == 0 && fixMeCurrentNumber <= maxValue )){
            ArrayList<Integer> fixMeList = new ArrayList<>();
            fixMeList.add(fixMeCurrentNumber);
            wrapper.setSavedNumbers(fixMeList);
            wrapper.setCurrentTotalOfList(fixMeCurrentNumber);
        }
        else {
            ArrayList<Integer> copyToBeItereatedOver = new ArrayList<>();
            copyToBeItereatedOver = wrapper.getSavedNumbers();
            copyToBeItereatedOver.stream().forEach(savedNumber -> {
                 validateSavedNumbers(maxValue, wrapper, fixMeCurrentNumber);
            });
        }
        return wrapper.getSavedNumbers();
    }

    private static void validateSavedNumbers(int maxValue, Wrapper wrapper,
                                             Integer fixMeCurrentNumber) {
        if(wrapper.getCurrentTotalOfList() < maxValue &&
                wrapper.getCurrentTotalOfList() + fixMeCurrentNumber <= maxValue) {
            ArrayList<Integer> savedNumbers = new ArrayList<>();
            savedNumbers = wrapper.getSavedNumbers();
            //tried passing a wrapper and still no luck.
            savedNumbers.add(fixMeCurrentNumber);
            //wrapper.setSavedNumbers(savedNumbers);
            //wrapper.setCurrentTotalOfList(wrapper.getCurrentTotalOfList() + fixMeCurrentNumber);
        }
    }
}




---------------

package models;

import lombok.Data;

import java.util.ArrayList;


@Data
public class Wrapper {
    ArrayList<Integer> savedNumbers;
    int currentTotalOfList;
}
---------------

the issue is where I have savedNumbers.add(fixMeCurrentNumber); it then throws the ConcurrentModificationException.

Any suggestions on how you would go about fixing this?

passing a nested object wrapper for the wrapper.savedNumbers - did not work my next guess was to try an itorator - but am trying not to do that as I want to stick to using streams.

Maybe there is a easier way to do it where I do not do nested streams? o.o

shmosel
  • 49,289
  • 6
  • 73
  • 138

2 Answers2

0

In your computeLogic method, you have a Wrapper instance.

In the body of the else block in that same method, you have:

copyToBeItereatedOver = wrapper.getSavedNumbers();

However, despite the variable name, it is not a copy. It’s the very same ArrayList that is contained in the Wrapper, and that is the source of your troubles.

The very next thing your code does is:

copyToBeItereatedOver.stream().forEach(savedNumber -> {
     validateSavedNumbers(maxValue, wrapper, fixMeCurrentNumber);
});

You are passing the same Wrapper object to validateSavedNumbers, while using a Stream to iterate over the Wrapper object’s savedNumbers List. And what does validateSavedNumbers do with that Wrapper object? It does this:

savedNumbers = wrapper.getSavedNumbers();
savedNumbers.add(fixMeCurrentNumber);

It’s trying to add to the very same List that the computeLogic method is already iterating over. That’s why you’re seeing a ConcurrentModificationException.

The easiest solution is to make sure copyToBeItereatedOver is actually a copy, as its name implies. Change this:

copyToBeItereatedOver = wrapper.getSavedNumbers();

to this:

copyToBeItereatedOver = List.copyOf(wrapper.getSavedNumbers());

(If, for some reason, you’re using an old version of Java, and the compiler doesn’t recognize List.copyOf, you can use copyToBeItereatedOver = new ArrayList<>(wrapper.getSavedNumbers()); instead.)

VGR
  • 40,506
  • 4
  • 48
  • 63
  • Thank you so much VGR. I knew it was something to do with the wrapper and thought my copy might not be working right, but my brain was mush after looking at the code for too long. Thanks! both ways worked. I learned something to make sure my copy's actully create new objects and not reuse existing references, and the .copyOf method of list. I learned so much from this problem. like who to use wrappers to use varibles inside lamdas, and how to get into breakpoints inside streams .map by creating methods. Thank you for your help VGR *high five* thanks! – David Westenberger Mar 10 '23 at 03:39
0

Working solution to the problem posted below thanks to VGR comment.


    package com.example.demo_david;

import models.Wrapper;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@SpringBootApplication
public class DemoDavidApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoDavidApplication.class, args);

        Integer value = 13;
        List<Integer> fixMe = new ArrayList<>(List.of(6,4,7,9,3,12));
        System.out.println("answer: " + findTheOnesThatEqualTheResult(value, fixMe));
    }

    static List<Integer> findTheOnesThatEqualTheResult(int maxValue, List<Integer> list){
        Wrapper wrapper = new Wrapper();
        list.stream().map(fixMeCurrentNumber ->
                computeLogic(maxValue, wrapper, fixMeCurrentNumber)).collect(Collectors.toList());
        return wrapper.getSavedNumbers();
    }

    private static ArrayList<Integer> computeLogic(int maxValue, Wrapper wrapper, Integer fixMeCurrentNumber) {
        if((wrapper.getSavedNumbers() == null && fixMeCurrentNumber <= maxValue) ||
                (wrapper.getSavedNumbers().size() == 0 && fixMeCurrentNumber <= maxValue )){
            ArrayList<Integer> fixMeList = new ArrayList<>();
            fixMeList.add(fixMeCurrentNumber);
            wrapper.setSavedNumbers(fixMeList);
            wrapper.setCurrentTotalOfList(fixMeCurrentNumber);
        }
        else {
            //List<Integer> copyToBeItereatedOver = new ArrayList<>();
            //copyToBeItereatedOver = List.copyOf(wrapper.getSavedNumbers());
            ArrayList<Integer> copyToBeItereatedOver = new ArrayList<>(wrapper.getSavedNumbers());
            copyToBeItereatedOver.stream().forEach(savedNumber -> {
                 validateSavedNumbers(maxValue, wrapper, fixMeCurrentNumber);
            });
        }
        return wrapper.getSavedNumbers();
    }

    private static void validateSavedNumbers(int maxValue, Wrapper wrapper,
                                             Integer fixMeCurrentNumber) {
        if(wrapper.getCurrentTotalOfList() < maxValue &&
                wrapper.getCurrentTotalOfList() + fixMeCurrentNumber <= maxValue) {
            ArrayList<Integer> savedNumbers = new ArrayList<>();
            savedNumbers = wrapper.getSavedNumbers();
            savedNumbers.add(fixMeCurrentNumber);
            wrapper.setSavedNumbers(savedNumbers);
            wrapper.setCurrentTotalOfList(wrapper.getCurrentTotalOfList() + fixMeCurrentNumber);
        }
    }
}
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 14 '23 at 20:11