Guava Supplier : transforming a collection with each element's own function - java

Let's say I have a Node class that has a Function as an instance variable.
public class Node {
private Function<Node, Double> function;
...
I have a List of these Nodes:
List<Node> nodes = Lists.newLinkedList();
nodes.add(new Node(someFunction));
nodes.add(new Node(someOtherFunction));
I can do this:
public Collection<Double> getValues() {
SomeFunction f = new SomeFunction();
return Collections2.transform(nodes, f);
}
Sure enough, transform iterates over the nodes List and applies the function f to each element like mapcar.
What I'm trying to do is to have transform use the function that each node element has.
So I though that the Supplier would help.
class NodeSupplier implements Supplier<Node> {
Iterator<Node> iterator;
NodeSupplier(Iterable p) {
iterator = Iterators.cycle(p);
}
#Override
public Node get() {
return iterator.next();
}
}
Then a Function to get a Node.
class SupplierGetter implements Function<Supplier<Node>, Node> {
#Override
public Node apply(Supplier<Node> from) {
return from.get();
}
}
Then compose them:
FunctionGetter fg = new FunctionGetter();
NodeSupplier sup = new NodeSupplier(this); // the this class is Iterable
Supplier<Function<Node, Double>> supplier = Suppliers.compose(fg, sup);
But then it gives me a type mismatch when I try to use it:
Collections2.transform(nodes, supplier);
it wants suppler.get() which is called once.
Collections2.transform(nodes, supplier.get());
Is there an easier way?
I saw mention of
Suppliers.supplierFunction()
but that seem s to not exist in verison r09.

I'm confused by what you're trying to do... Supplier doesn't seem useful here. Each Node has its own Function. You want to transform a collection of Nodes by applying each Node's Function to itself. So why not just give the Node class some method:
// may want a better name
public Double applyFunction() {
return function.apply(this);
}
Then you'd just transform using a Function like this:
public Double apply(Node node) {
return node.applyFunction();
}

Apart from the fact that I also have my doubts about what you are trying to do, the following should achieve what you are asking for:
class Node {
private Function<Node, Double> function;
private static Function<Node,Double> applyFunction = new Function<Node,Double>() {
#Override
public Double apply(final Node input) {
return input.function.apply(input);
}
};
public static Iterable<Double> transform(final Iterable<Node> nodes) {
return Iterables.transform(nodes, applyFunction);
}
}

There is a third way to do this without modifying the Node class, if we suppose that Node exposes its function through a public getter.
Using an anonymous class :
public Collection<Double> getValues() {
return Collections2.transform(nodes, new Function<Node, Double>() {
#Override public Double apply(Node node) {
return node.getFunction().apply(node);
}
});
}
Using the enum singleton pattern (which I prefer, since it's clearer) :
public Collection<Double> getValues() {
return Collections2.transform(nodes, ApplyNodeFunction.INSTANCE);
}
/**
* A {#link Function} that applies the {#link Node}'s own function on itself.
*/
private enum ApplyNodeFunction implements Function<Node, Double> {
INSTANCE;
#Override public Double apply(Node node) {
return node.getFunction().apply(node);
}
}

The key to my question was this phrase: "So I thought that the Supplier would help." The answer is that it doesn't. I was trying to find a use for it - outside of Map creation which seems to be its main use. There was that one Suppliers method I mentioned but it seems to be MIA. Perhaps this could be an RFI for tranform be overloaded to take an Iterable as the second parameter

Related

Create a neat method out of three similar ones using generics

I've tried to do some stuff with generics already but it seems I cannot personally find any simple solution. Still I think it'd be a sin to leave these 3 similar methods alone as they are.
public List<PassengerPlane> getPassengerPlanes() {
List<PassengerPlane> passengerPlanes = new ArrayList<>();
for (Plane plane : planes) {
if (plane instanceof PassengerPlane) {
passengerPlanes.add((PassengerPlane) plane);
}
}
return passengerPlanes;
}
public List<MilitaryPlane> getMilitaryPlanes() {
List<MilitaryPlane> militaryPlanes = new ArrayList<>();
for (Plane plane : planes) {
if (plane instanceof MilitaryPlane) {
militaryPlanes.add((MilitaryPlane) plane);
}
}
return militaryPlanes;
}
public List<ExperimentalPlane> getExperimentalPlanes() {
List<ExperimentalPlane> experimentalPlanes = new ArrayList<>();
for (Plane plane : planes) {
if (plane instanceof ExperimentalPlane) {
experimentalPlanes.add((ExperimentalPlane) plane);
}
}
return experimentalPlanes;
}
What do you need is generic method, but the problem is that instanceof cannot check against type parameter (it is in fact erased during compilation), it requires actual class reference. So, you may provide this to the method explicitly:
public <T extends Plane> List<T> getPlanes(Class<T> claz) {
List<T> result = new ArrayList<>();
for (Plane plane : planes) {
if (claz.isInstance(plane)) {
result.add(claz.cast(plane));
}
}
return result;
}
Note how instanceof and explicit cast changed to calls to .isInstance() and .cast()
Use it like
getPlanes(PassengerPlane.class)
You can make things a bit shorter with Streams, but I'm not sure there's a way to get around using instanceof here:
public List<PassengerPlane> getPassengerPlanes() {
return planes.stream().filter(t -> t instanceof PassengerPlane)
.map(t -> (PassengerPlane) t).collect(Collectors.toList());
}
public List<MilitaryPlane> getMilitaryPlanes() {
return planes.stream().filter(t -> t instanceof MilitaryPlane)
.map(t -> (MilitaryPlane) t).collect(Collectors.toList());
}
public List<ExperimentalPlane> getExperimentalPlanes() {
return planes.stream().filter(t -> t instanceof ExperimentalPlane)
.map(t -> (ExperimentalPlane) t).collect(Collectors.toList());
}
Here's how I would approach the problem using generics:
public <T> List<T> getTPlanes(Class<T> clazz) { //declare the method to take a type generic
List<T> tPlanes = new ArrayList<>(); //initialize an ArrayList of that type
planes.stream() //stream the planes list
.filter(clazz::isInstance) //filter it down to only planes of the type that we want
.forEach((p) -> tPlanes.add((T) p)); //add each plane left in the stream to our new ArrayList, and cast it to the type generic
return tPlanes; //return the ArrayList we just created and populated
}
You do need to do a cast somewhere: Here is a solution with a single method that takes the subtype.
import java.util.*;
import java.util.stream.*;
public class Example {
public static class Plane { }
public static class PassengerPlane extends Plane { }
public static class MilitaryPlane extends Plane { }
public static class ExperimentalPlane extends Plane { }
private static List<Plane> planes =
List.of(new PassengerPlane(),
new MilitaryPlane(),
new ExperimentalPlane());
public static <T extends Plane> List<T> getPlanesOfType(Class<T> type, List<Plane> planes) {
List<T> list =
planes.stream()
.filter(t -> type.isAssignableFrom(t.getClass()))
.map(t -> type.cast(t))
.collect(Collectors.toList());
return list;
}
public static void main(String[] args) throws Exception {
System.out.println(getPlanesOfType(PassengerPlane.class, planes));
System.out.println(getPlanesOfType(MilitaryPlane.class, planes));
System.out.println(getPlanesOfType(ExperimentalPlane.class, planes));
System.out.println(getPlanesOfType(Plane.class, planes));
}
}
[Example$PassengerPlane#7b227d8d]
[Example$MilitaryPlane#7219ec67]
[Example$ExperimentalPlane#45018215]
[Example$PassengerPlane#7b227d8d, Example$MilitaryPlane#7219ec67, Example$ExperimentalPlane#45018215]
You could either use the single method to replace all three or use it to implement.
If your problem is really so short, probably it won't be worthy the effort. However, this is a typical problem for Visitor Pattern (especially if your duplicate code is larger).
Step 1
Create a Visitor interface to visit each type of Plane:
interface Visitor {
void visit(MilitaryPlane militaryPlane);
void visit(ExperimentalPlane experimentalPlane);
void visit(PassengerPlane passengerPlane);
}
... and implement it in a way that starts with a List<Plane> that can be enriched by each of the .visit():
class PlaneVisitor implements Visitor {
private final List<Plane> planes;
PlaneVisitor(List<Plane> planes) {
this.planes = requireNonNull(planes);
}
#Override
public void visit(MilitaryPlane militaryPlane) {
planes.add(militaryPlane);
}
#Override
public void visit(ExperimentalPlane experimentalPlane) {
planes.add(experimentalPlane);
}
#Override
public void visit(PassengerPlane passengerPlane) {
planes.add(passengerPlane);
}
public List<Plane> getPlanes() {
return planes;
}
}
Step 2 - Enable visitors in your classes
Add an abstract method in your base class Plane to accept the visitor:
public abstract class Plane {
//...
abstract void accept(Visitor visitor);
//...
}
Then implement this method in each sub-class to let the Visitor instance visit itself (this). Example for PassengerPlane (same logic for all the other classes):
public class PassengerPlane extends Plane {
//...
#Override
void accept(Visitor visitor) {
visitor.visit(this);
}
//...
}
Step 3 - Adapt your function
Your function can now loop through the list of planes not caring about the type. It will be resolved by the visitor:
public List<Plane> getPlanes() {
PlaneVisitor planeVisitor = new PlaneVisitor(new ArrayList<>());
for (Plane plane : planes) {
plane.accept(planeVisitor);
}
return planeVisitor.getPlanes();
}
Note that you need to add a bit of methods / interfaces to do this. Since your code is very small, you can imagine to leave it like it is even if it's not very "elegant". However, the above example can be of inspiration if your code is actually supposed to do more than what you're showing us.
It can be done in this way by introduced a method that do common part:
private static <T> List<T> createFilteredList(List<Plane> inList, Class<T> clazz) {
List<T> outList = new ArrayList<>();
for (Plane value : inList) {
if (clazz.isInstance(value)) {
outList.add(clazz.cast(value));
}
}
return outList;
}
Then it can be used like this:
public List<PassengerPlane> getPassengerPlanes() {
return createFilteredList(planes, PassengerPlane.class);
}
public List<MilitaryPlane> getPassengerPlanes() {
return createFilteredList(planes, MilitaryPlane.class);
}
public List<ExperimentalPlane> getPassengerPlanes() {
return createFilteredList(planes, ExperimentalPlane.class);
}
So, you have an iterable of Plane as an input.
A Plane can be PassengerPlane, MilitaryPlane or ExperimentalPlane.
What you are trying to do is to filter a collection of planes by a predicate. A predicate is a function that takes a Plane and answers true or false. A filter uses a predicate to figure out whether to include a given item into the result or to skip.
If you are using Java 8 or later version, you can use the Streams API.
https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html
Produce a stream from the planes iterable.
Apply filter to it (intermediate operation).
Collect the results to list.
Using Stream API you can convert the methods above into one-liners. Like this:
planes.stream().filter(plane -> plane instanceof MilitaryPlane).collect(toList());
Then, probably, you won't need a separate neat method for it.
But if you want some reusable piece of code, then you have to figure out what is the parameter here. In the code above it is a specific plane implementation:
public List<Plane> filterPlanes(Iterable<Plane> planes, Class<? extends Plane> planeImplementation)
So, you can build a predicate with this parameter:
plane -> planeImplementation.isInstance(plane)
If you have a Plane supertype, you can make the subclasses inherit the getPlanes() method. this.getClass will extract only the planes of the subclass calling the method from the list. This way, you don't have to pass a class to the method, as it can be derived from the subclass that is calling it.
public abstract class Plane {
public Plane(){}
public List<Plane> getPlanes() {
List<Plane> result = new ArrayList<>();
for (Plane plane : planes) {
if (this.getClass().isInstance(plane)) {
result.add(this.getClass().cast(plane));
}
}
return result;
}
}
class PassengerPlane extends Plane {
}
class MilitaryPlane extends Plane {
}
class ExperimentalPlane extends Plane {
}
public class PlaneList {
public String name;
public static ArrayList<Plane> planes = new ArrayList<>();
public PlaneList(){
planes.add(new MilitaryPlane());
planes.add(new MilitaryPlane());
planes.add(new MilitaryPlane());
planes.add(new PassengerPlane());
planes.add(new PassengerPlane());
planes.add(new ExperimentalPlane());
}
}
I tested it like so:
public class Main {
public static void main(String[] args) {
PlaneList list = new PlaneList();
Plane plane = new PassengerPlane();
for(Plane p : plane.getPlanes()){
System.out.println(p.toString());
}
}
}
output:
com.company.PassengerPlane#7dc36524
com.company.PassengerPlane#35bbe5e8

How to implement Filtering Iterator in Java?

I have created an array (tab[]) of objects and now I need to filter and print via one of their fields (ex. print if ob.a>1 ). I created an Iterator interface, ArrayIterator that goes through all entries on list and Predicate interface. This is constructor of my FilteringIterator:
private final Iterator iterf;
private final Predicate pred;
public FilteringIterator(ArrayIterator i, Predicate predykat)
{
iterf=i;
pred=predykat;
iterf.first();
}
Method that prints every entry using my "basic" iterator looks like this:
public void printlist()
{
ArrayIterator itab =new ArrayIterator(lista);
for(itab.first();!itab.isDone(); itab.next())
{
Student stud=(Student)itab.current();
stud.show();
}
}
I also have a class that implements Predicate interface:
public interface Predicate
{
public boolean accept(Object ob);
}
How to use my FilteringIterator, when it requires Predicate, and I cannot create such object, as it's an interface?
Sounds like you want to implement next() in FilteringIterator class.
It should be something like:
public T next() {
T next = iterf.next();
while (!pred.accept(next))
next = iterf.next();
return next;
}
Now that you see next() it should be an easy exercise to implement hasNext() as well!
In order to create a predicate you should implement Predicate interface, for example:
class MyPredicate implements Predicate {
#Override
public boolean accept(Object ob){
if (!ob instanceof Student)
return false;
Student student = (Student) ob;
return student.a > 1;
}
}

Find the root of a hierarchy, using Optional

I have a tree hierarchy of types that are aware of their children, but not their parents. Now I am creating an external registry that provides the opposite path, from the outside:
public interface Registry<X>{
Optional<X> parent(X node);
}
Now I'd like to implement a method in that interface, that gets the root note of this hierarchy from any given node (the root node can be the node passed in or any ancestor).
I got this far:
default X root(X node) {
X current = node;
for (Optional<X> opt = Optional.of(current);
opt.isPresent();
opt = opt.flatMap(this::parent)) {
if (opt.isPresent()) {
current = opt.get();
}
}
return current;
}
While this works, it feels kinda clumsy. Optional.isPresent() is called twice, and the variable current is re-assigned. Is there any way I can make this more elegant and functional?
I'm thinking of
default X root(X node) {
X root = node;
for (Optional<X> parentOpt = parent(root); parentOpt.isPresent(); root = parentOpt.get())
;
return root;
}
I don't like dealing with null arguments. So we defer to parent's implementation, which you'll probably document as returning an empty Optional on null argument.
If the argument is null, we'll also return null.
If the argument is not null, we save its value in root and start looping. We get its potential parent. If it's present, we update root, and retry. Otherwise, we break, and return the last saved value in root, since that's as far as we got.
That clumsy feeling, I think, comes from the initial Optional around node. I don't think you need that.
The answer by #Sotirios is concise and more than good enough.
You implemented an Iterator in your attempt at a solution and my solution is to implement it as a Spliterator/Stream. It's probably overly complicated for your particular question, but it could be useful elsewhere for your library, or it could be useful for someone else browsing stackoverflow.
public class ParentSpliterator<T> implements Spliterator<T> {
private final Registry<T> registry;
private Optional<T> currentNodeOpt;
public ParentSpliterator(Registry<T> registry, T startNode) {
this.registry = registry;
this.currentNodeOpt = Optional.of(startNode);
}
#Override
public boolean tryAdvance(Consumer<? super T> action) {
if (!currentNodeOpt.isPresent()) {
return false; // stream is empty
} else {
T currentNode = currentNodeOpt.get();
action.accept(currentNode);
currentNodeOpt = registry.parent(currentNode);
return true;
}
// // Alternative implementation (more Stream-ish):
// return currentNodeOpt.map(node -> {
// action.accept(node);
// currentNodeOpt = registry.parent(node);
// return node;
// }).isPresent();
}
#Override
public Spliterator<T> trySplit() {
return null; // Cannot be split.
}
#Override
public long estimateSize() {
return Long.MAX_VALUE; // No quick way to estimate size.
}
#Override
public int characteristics() {
return Spliterator.ORDERED; // maybe others?
}
public static void main(String[] args) {
Registry.CountDownRegistry cdr = new Registry.CountDownRegistry();
ParentSpliterator<Integer> parentSpliterator = new ParentSpliterator<>(cdr, 3);
Stream<Integer> stream = StreamSupport.stream(parentSpliterator, false);
//stream.forEach(System.out::println);
// Using a reduce to pick the last element of the Stream:
Integer root = stream.reduce((node, nextNode) -> nextNode).get();
System.out.println(root);
}
}
And you need this utility class to get the example to work:
public interface Registry<X> {
Optional<X> parent(X node);
public static class CountDownRegistry implements Registry<Integer> {
#Override
public Optional<Integer> parent(Integer node) {
if (node > 0) {
return Optional.of(node - 1);
} else {
return Optional.empty();
}
}
}
}
Guava and JDK stream versions below, but the absolute winner is JavaSlang. I love it!
import javaslang.collection.Stream;
import java.util.Optional;
// ...
default X root(X node) {
return Stream.iterate(Optional.of(node),
t -> t.flatMap(this::parent)
).takeWhile(Optional::isPresent)
.last()
.orElseThrow(NoSuchElementException::new);
}
The Stream.iterate() method is exactly what I'm missing in the two other versions.
Guava:
First we'll create a helper class called Optionals:
// to avoid misunderstandings:
import java.util.Optional;
import java.util.function.Function;
import com.google.common.collect.AbstractIterator;
public final class Optionals {
private Optionals(){}
/**
* Given an instance of type T and a function from T to Optional<T>,
* return an Iterable<T>. This Iterable will keep returning values
* by repeatedly applying the supplied function until the returned Optional
* is not present.
*/
public static <T> Iterable<T> stream(
final T start, final Function<T, Optional<T>> increment) {
return () -> new AbstractIterator<T>() {
Optional<T> current = Optional.of(start);
#Override
protected T computeNext() {
if (!current.isPresent()) return endOfData();
final T data = current.get();
current = current.flatMap(increment);
return data;
}
};
}
}
This is of course even more boilerplate, but that's re-usable, and now we can write the interface method in a concise way:
default X root(final X node) {
return Iterables.getLast(Optionals.stream(node, this::parent));
}
Obviously it would be possible to implement this without Guava, but it would be a lot messier.
Java 8 Stream version:
public final class Streams {
private Streams(){}
/**
* Given an instance of type T and a function from T to Optional<T>,
* return a Stream<T>. This Stream will keep returning values by
* repeatedly applying the supplied function until the returned Optional
* is not present.
*/
public static <X> Stream<X> stream(
final X start, final Function<X, Optional<X>> increment) {
return StreamSupport.stream(
new Spliterator<X>() {
Optional<X> next = Optional.ofNullable(start);
#Override
public boolean tryAdvance(final Consumer<? super X> action) {
final boolean present = next.isPresent();
if (present) action.accept(next.get());
next = next.flatMap(increment);
return present;
}
#Override
public Spliterator<X> trySplit() { return null; }
#Override
public long estimateSize() { return Long.MAX_VALUE; }
#Override
public int characteristics() { return Spliterator.ORDERED; }
}, false
);
}
Which leads to this code:
default X root(final X node) {
return Streams.stream(node, this::parent)
.reduce((left, right) -> right)
.orElseThrow(NoSuchElementException::new);
}
I think you're pretty close already with the loop you tried. It can be simplified a bit since the loop body is only executed if the loop condition is true, so you don't have to retest opt.isPresent within the loop. You can save a variable if you reuse the node parameter. (I know, it's a style thing.) The flatMap call in the increment part doesn't buy you much because you know that opt is present at that point; you might as well just call parent on the result of opt.get while assigning node while you're at it. This gives:
default X root(X node) {
for (Optional<X> opt = Optional.of(node); opt.isPresent(); opt = parent(node = opt.get()))
;
return node;
}
You pretty much have to assume that node is non-null, so you can move the parent call into the loop condition, simplifying things a bit:
default X root(X node) {
for (Optional<X> opt; (opt = parent(node)).isPresent(); node = opt.get())
;
return node;
}
Java 9 will have a new three-arg Stream.iterate factory that lets you create a leaf-to-root stream of nodes quite conveniently. The three arguments are just like the three statements of a for-loop, except they can't have side effects. You can transliterate your original for-loop into a stream as follows:
default Stream<X> stream(X node) {
return Stream.iterate(Optional.of(node),
Optional::isPresent,
op -> op.flatMap(this::parent))
.map(Optional::get);
}
Finally, there is this:
default X root(X node) {
return Optional.of(node).flatMap(this::parent).map(this::root).orElse(node);
}
There are several things of note regarding this technique.
It violates one of the style rules for Optional that I've been espousing, in particular this one: "#4: It's generally a bad idea to create an Optional for the specific purpose of chaining methods from it to get a value." (link)
It's recursive, which means it can blow your stack if your hierarchy is too deep.
Your coworkers will shun you if you use this technique.
I don't recommend writing code like this, but I wanted to put it out there before somebody else did. :-)

Need a sorted collection of pairs capable of performing floor operation based only on the first member of the pair

I appologize for the title. I don't know what this computational problem is called.
I was hoping there was a collection class ready for me to use to solve this. I use TreeSet in the example bellow just to show what I need. I believe the example to be clear enough to explain the question.
public class MyClass
{
//I know TreeSet doesn't work. Is there a collection that would work like TreeSet
//but has a method similar to the imaginary overload of TreeSet.floor I invoke in my code?
private TreeSet<OrderElement<Integer, Object>> treeSet = new TreeSet<>();
//this method is irrelevant to the problem.
//it's here just for usability of this example class
public void addElement(int order, Object element)
{
treeSet.add(new OrderElement(order, element));
}
//this is the method I need to implement
public Object floor(int order)
{
//this overload does not exist. I need a collection with a similar function
return treeSet.floor(order);
}
}
//this class represents the elements in the TreeSet.
public class OrderElement<O extends Comparable, E>, implements Comparable<O>
{
public final O order;
public final E element;
public OrderElement(O order, E element)
{
this.order = order;
this.element = element;
}
#Override
public int compareTo(O param)
{
return this.order.compareTo(param);
}
#Override
public boolean equals(Object obj)
{
return obj.equals(this.order);
}
#Override
public int hashCode()
{
return this.order.hashCode();
}
}
You want to use TreeMap<Integer, Object> and your floor method is called floorKey there
http://docs.oracle.com/javase/7/docs/api/java/util/TreeMap.html#floorKey(K)

Provide an iterator over the contents of two lists simultaneously?

Suppose I have this:
public class Unit<MobileSuit, Pilot> {
...
List<MobileSuit> mobileSuits;
List<Pilot> pilots;
...
}
And I would like to iterate through the pair of each in the simplest way outside of that class. How should I go about doing that? I thought about doing this:
public class Unit<MobileSuit, Pilot> {
...
Iterator<MobileSuit> iteratinMechas;
Iterator<Pilot> iteratinPeople;
class IteratorCustom<MobileSuit, Pilot> implements Iterator {
public boolean hasNext() {
return iteratinMechas.hasNext() && iteratinPeople.hasNext();
}
public void remove() {
iteratinMechas.remove();
iteratinPeople.remove();
}
public Object next() {
// /!\
}
}
public Iterator iterator() {
return new IteratorCustom<MobileSuit, Pilot>(mobileSuits, pilots);
}
}
Something along those lines.
Anyway, the problem is that I can't really return just a single object from next(), and I also can't have a Iterator take more than one type. So, any thoughts?
Also, I can't make a new class to combine MobileSuit and Pilot. I need to keep them separate, even though I'm iterating through both at a time. The reason is that there might be Mobile Suits that have no pilots, and I'm not sure how to fix that by keeping them at the same class. This class needs to be processed in other places, so I'd have to unify a interface around that and a lot of other stuff. Basically, assume MobileSuit and Pilot need to be separated.
Anyway, the problem is that I can't really return just a single object from next(), and I also can't have a Iterator take more than one type. So, any thoughts?
Obviously you are going to need a light-weight "pair" class. This is roughly analogous to the Map.Entry inner class.
Here's a rough cut at a generic solution:
public class ParallelIterator <T1, T2> implements Iterator<Pair<T1, T2>> {
public class Pair<TT1, TT2> {
private final TT1 v1;
private final TT2 v2;
private Pair(TT1 v1, TT2 v2) { this.v1 = v1; this.v2 = v2; }
...
}
private final Iterator<T1> it1;
private final Iterator<T2> it2;
public ParallelIterator(Iterator<T1> it1, Iterator<T2> it2) {
this.it1 = it1; this.it2 = it2;
}
public boolean hasNext() { return it1.hasNext() && it2.hasNext(); }
public Pair<T1, T2> next() {
return new Pair<T1, T2>(it1.next(), it2.next());
}
...
}
Note: this doesn't explicitly deal with cases where the lists have different lengths. What will happen is that extra elements at the end of the longer list will be silently ignored.
This is copied+edited from Stephen C's answer. Feel free to use:
public class Pair<T1, T2> {
private final T1 v1;
private final T2 v2;
Pair(T1 v1, T2 v2) {
this.v1 = v1;
this.v2 = v2;
}
public T1 first(){
return v1;
}
public T2 second(){
return v2;
}
}
public class ParallelIterator <T1, T2> implements Iterator<Pair<T1, T2>> {
private final Iterator<T1> it1;
private final Iterator<T2> it2;
public ParallelIterator(Iterator<T1> it1, Iterator<T2> it2) {
this.it1 = it1; this.it2 = it2;
}
#Override
public boolean hasNext() { return it1.hasNext() && it2.hasNext(); }
#Override
public Pair<T1, T2> next() {
return new Pair<T1, T2>(it1.next(), it2.next());
}
#Override
public void remove(){
it1.remove();
it2.remove();
}
}
public class IterablePair <T1, T2> implements Iterable<Pair<T1,T2>> {
private final List<T1> first;
private final List<T2> second;
public IterablePair(List<T1> first, List<T2> second) {
this.first = first;
this.second = second;
}
#Override
public Iterator<Pair<T1, T2>> iterator(){
return new ParallelIterator<T1,T2>( first.iterator(), second.iterator() );
}
}
void someFunction(){
IterablePair<X,Y> listPair = new IterablePair<X,Y>( x, y );
for( Pair<X,Y> pair : listPair ){
X x = pair.first();
...
}
}
This stops as soon as either list is out of elements, so you might want to check lists have equal size before creating an IterablePair.
Also, I can't make a new class to combine MobileSuit and Pilot.
That doesn't sound correct. It sounds like you can't replace MobileSuit and Pilot by a single class, but I don't see any reason why you can't have a single class that combines them - i.e. one which just has a getPilot() method and a getMobileSuit() method. You could use a generic Pair class for the same purpose, but a custom class would be easier to use.
On the other hand, if you want to do this sort of "zipping" operation in multiple places, it might be one solution. Alternatively, you could write a generic interface to represent the act of combining the two distinct items - which could return a SuitedPilot or whatever your combination class is.
The reason is that there might be Mobile Suits that have no pilots, and I'm not sure how to fix that by keeping them at the same class.
You can use null values, right? Which is the correct way of doing it - have each suit keep track of its pilot. If it has no pilot, then indicate that with a null value there.
But, if you're dead set on not doing that for some reason...
public class SuitAndPilot
{
public MobileSuit suit;
public Pilot pilot;
public SuitAndPilot(Suit s, Pilot p) {
suit = s;
pilot = p;
}
}
Why not have a class MannedMobileSuit as a subclass of MobileSuit that contains an instance of a pilot ? That would solve your problem by having a getPilot method.
Usually when you get such problems (needing to return two instances) it is because your Object model is not appropriate and should be changed. Keep your options open
Came across this page trying to solve this issue, and turns out that there's a library out there that's already solved it using Java 8 streams (check out the Zip function).
You can convert a list to a stream just by calling list.stream()
https://github.com/poetix/protonpack
Stream<String> streamA = Stream.of("A", "B", "C");
Stream<String> streamB = Stream.of("Apple", "Banana", "Carrot", "Doughnut");
List<String> zipped = StreamUtils.zip(streamA,
streamB,
(a, b) -> a + " is for " + b)
.collect(Collectors.toList());
assertThat(zipped,
contains("A is for Apple", "B is for Banana", "C is for Carrot"));
Basically, assume MobileSuit and Pilot need to be separated.
That's fine, but here you're trying to treat them as a unit, so structure your code that way. The suggestions above use a Pair class or Map.Entry, but it's much better to provide a clearly-named object that represents a MobileSuit with a Pilot, e.g.:
public class OccupiedSuit {
private final MobileSuit suit;
private final Pilot pilot;
public OccupiedSuit(MobileSuit suit, Pilot pilot) {
this.suit = checkNotNull(suit);
this.pilot = checkNotNull(pilot);
}
// getters, equals, hashCode, toString
// or just use #AutoValue: https://github.com/google/auto/tree/master/value
}
Then, rather than constructing a custom Iterator/Iterable, just write a helper function that zips up the two lists. For example:
public static List<OccupiedSuit> assignPilots(
Iterable<MobileSuit> suits, Iterable<Pilot> pilots) {
Iterator<MobileSuit> suitsIter = suits.iterator();
Iterator<Pilot> pilotsIter = pilots.iterator();
ImmutableList.Builder<OccupiedSuit> builder = ImmutableList.builder();
while (suitsIter.hasNext() && pilotsIter.hasNext()) {
builder.add(new OccupiedSuit(suitsIter.next(), pilotsIter.next()));
}
// Most of the existing solutions fail to enforce that the lists are the same
// size. That is a *classic* source of bugs. Always enforce your invariants!
checkArgument(!suitsIter.hasNext(),
"Unexpected extra suits: %s", ImmutableList.copyOf(suitsIter));
checkArgument(!pilotsIter.hasNext(),
"Unexpected extra pilots: %s", ImmutableList.copyOf(pilotsIter));
return builder.build();
}
Now you don't need to maintain a complex custom Iterator implementation - just rely on one that already exists!
We can also generalize assignPilots() into a generic utility that works for any two inputs, like so:
public static <L,R,M> List<M> zipLists(
BiFunction<L,R,M> factory, Iterable<L> left, Iterable<R> right) {
Iterator<L> lIter = left.iterator();
Iterator<R> rIter = right.iterator();
ImmutableList.Builder<M> builder = ImmutableList.builder();
while (lIter.hasNext() && rIter.hasNext()) {
builder.add(factory.apply(lIter.next(), rIter.next()));
}
checkArgument(!lIter.hasNext(),
"Unexpected extra left elements: %s", ImmutableList.copyOf(lIter));
checkArgument(!rIter.hasNext(),
"Unexpected extra right elements: %s", ImmutableList.copyOf(rIter));
return builder.build();
}
Which you'd then invoke like so:
List<OccupiedSuit> occupiedSuits = zipLists(OccupiedSuit::new, suits, pilots);
Example code uses Guava's Preconditions and ImmutableList - if you don't use Guava it's easy enough to inline and swap to ArrayList, but just use Guava :)
for(int i=0; i < mobileSuits.size(); i++) {
MobileSuit suit = mobileSuits.get(i);
Pilot pilot = pilots.get(i);
...
}
You could just use a Map<MobileSuit, Pilot>, where a null value mapped to a MobileSuit indicates no pilot. The Iterator could just be an Iterator<Map.Entry<MobileSuit, Pilot>> retrieved by map.entrySet().iterator().
Improving on the answer by user2224844, here is a simple version that will try no to run into an exception:
final Iterator<String> pilotIterator = pilots.iterator();
mobileSuits.forEach(m -> {
Pilot p = pilotIterator.hasNext()? pilotIterator.next():nullOrWahtever;
<Now do your work with m and p variables>
...
});
Isn't that enough ?
for(MobileSuit ms : MobileSuits) {
for(Pilot p : pilots){
//TODO
}
}

Categories

Resources