6

There is a old Java code (without lambda expressions):

public List<CheckerPosition> getAttackedCheckersForPoint(CheckerPosition from, boolean isSecondPlayerOwner, boolean isQueen, VectorDirection ignoredDirection){
    List<VectorDirection> allDirections = VectorDirection.generateAllDirections();
    List<CheckerPosition> result = new ArrayList<CheckerPosition>();

    for (VectorDirection direction : allDirections){
        if (!direction.equals(ignoredDirection)){
            Checker firstCheckerOnWay = findFirstCheckerOnWay(new CheckerBaseVector(from, direction), !isQueen);
            if ((firstCheckerOnWay != null) && (firstCheckerOnWay.isSecondPlayerOwner() != isSecondPlayerOwner) && isCheckerBlocked(firstCheckerOnWay.getPosition(), direction)){
                result.add(firstCheckerOnWay.getPosition());
            }
        }
    }
    return result;
 }

I'm trying to rewrite this code to Java 8 Stream API style:

allDirections.stream()
                .filter(d -> !d.equals(ignoredDirection))
                .map(d -> findFirstCheckerOnWay(new CheckerBaseVector(from, d), !isQueen)) // In this operation I map VectorDirection element (d) to Checker variable type.
                .filter(c -> (c != null) && (c.isSecondPlayerOwner() != isSecondPlayerOwner) && isCheckerBlocked(c.getPosition(), d)); // But in this operation I need to access d variable...

PROBLEM: The function isCheckerBlocked() (which uses in last filter() operation) takes variable of VectorDirection type (variable d). But after calling map() function I lose access to this variable. How I can save access to d variable after calling map() function?

Thank you for attention.

3
  • 2
    I'm afraid you can't access direction once you've mapped it to a new type. Maybe you can create a new object that encapsulates VectorDirection and Checker and you can map 'direction' to that type. Commented Feb 17, 2017 at 16:56
  • 3
    another possibility: in the mapping step, where both c and d are in scope, you could map to null if isCheckerBlocked Commented Feb 17, 2017 at 17:03
  • 2
    I am not sure if there is a good reason for rewriting it that way. I don't see how it would make the code more readable, mantainable, performant etc. Commented Feb 17, 2017 at 17:39

1 Answer 1

5

You cannot share scopes of lambdas like that. In other languages you can use tuples, so instead of returning just the result, you return result and argument.

In java you can create a custom class to host the pair of data you need or create a Tuple to host the pair of data .

public class Tuple<A,B> {
    public final A _1;
    public final B _2;
    public Tuple(A a, B b){
        _1 = a;
        _2 = b;
    }
    public static <A,B> Tuple<A,B> tuple(A a, B b){
        return new Tuple<>(a, b);
    }
}

Importing the tuple static function like this import static so.alpha.Tuple.tuple; you can map(tuple(d,f(d)))) then your next function will be filter(t->p(t._1,t._2)) and then you will map(t->t._1) or if you add getters to the tuple you can also map(Tuple::get_1)

That way you can carry on your d to the next step.

    Stream<String> s = Arrays.asList("sa","a","bab","vfdf").stream();

    Stream<Integer> result = s.map(d -> tuple(d.length(),d)) //String to Tuple<Integer,String>
        .filter(t->t._1 >= 2 && t._2.contains("a")) // Filter using both
        .map(Tuple::get_1); // Return just Integers
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.