I have a stream of objects like this:
"0", "1", "2", "3", "4", "5",
How can I transform it to stream of pairs :
{ new Pair("0", "1"), new Pair("2", "3"), new Pair("4", "5")}.
The stream size is unknown. I am reading data from a file that might be big. I have only iterator to collection and I transform this iterator to stream using spliterator.
I know that here is a answer for processing adjacent pairs with StreamEx :
Collect successive pairs from a stream
Can this be done in java or StreamEx ?
Thanks
It's not a natural fit but you can do
List input = ...
List<Pair> pairs = IntStream.range(0, input.size() / 2)
.map(i -> i * 2)
.mapToObj(i -> new Pair(input.get(i), input.get(i + 1)))
.collect(Collectors.toList());
To create Pairs as you go in a stream you need a stateful lambdas which should be generally avoided but can be done. Note: this will only works if the stream is single threaded. i.e. not parallel.
Stream<?> stream =
assert !stream.isParallel();
Object[] last = { null };
List<Pair> pairs = stream.map(a -> {
if (last[0] == null) {
last[0] = a;
return null;
} else {
Object t = last[0];
last[0] = null;
return new Pair(t, a);
}
}).filter(p -> p != null)
.collect(Collectors.toList());
assert last[0] == null; // to check for an even number input.
If you don't want to collect the elements
The title of the question says collect pairs from a stream, so I'd assume that you want to actually collect these, but you commented:
Your solution works, the problem is that it loads the data from file to PairList and then I may use stream from this collection to process pairs. I can't do it because the data might be too big to store in the memory.
so here's a way to do this without collecting the elements.
It's relatively straightforward to transform an Iterator<T> into an Iterator<List<T>>, and from that to transform a stream into a stream of pairs.
/**
* Returns an iterator over pairs of elements returned by the iterator.
*
* #param iterator the base iterator
* #return the paired iterator
*/
public static <T> Iterator<List<T>> paired(Iterator<T> iterator) {
return new Iterator<List<T>>() {
#Override
public boolean hasNext() {
return iterator.hasNext();
}
#Override
public List<T> next() {
T first = iterator.next();
if (iterator.hasNext()) {
return Arrays.asList(first, iterator.next());
} else {
return Arrays.asList(first);
}
}
};
}
/**
* Returns an stream of pairs of elements from a stream.
*
* #param stream the base stream
* #return the pair stream
*/
public static <T> Stream<List<T>> paired(Stream<T> stream) {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(paired(stream.iterator()), Spliterator.ORDERED),
false);
}
#Test
public void iteratorAndStreamsExample() {
List<String> strings = Arrays.asList("a", "b", "c", "d", "e", "f");
Iterator<List<String>> pairs = paired(strings.iterator());
while (pairs.hasNext()) {
System.out.println(pairs.next());
// [a, b]
// [c, d]
// [e, f]
}
paired(Stream.of(1, 2, 3, 4, 5, 6, 7, 8)).forEach(System.out::println);
// [1, 2]
// [3, 4]
// [5, 6]
// [7, 8]
}
If you want to collect the elements...
I'd do this by collecting into a list, and using an AbstractList to provide a view of the elements as pairs.
First, the PairList. This is a simple AbstractList wrapper around any list that has an even number of elements. (This could easily be adapted to handle odd length lists, once the desired behavior is specified.)
/**
* A view on a list of its elements as pairs.
*
* #param <T> the element type
*/
static class PairList<T> extends AbstractList<List<T>> {
private final List<T> elements;
/**
* Creates a new pair list.
*
* #param elements the elements
*
* #throws NullPointerException if elements is null
* #throws IllegalArgumentException if the length of elements is not even
*/
public PairList(List<T> elements) {
Objects.requireNonNull(elements, "elements must not be null");
this.elements = new ArrayList<>(elements);
if (this.elements.size() % 2 != 0) {
throw new IllegalArgumentException("number of elements must have even size");
}
}
#Override
public List<T> get(int index) {
return Arrays.asList(elements.get(index), elements.get(index + 1));
}
#Override
public int size() {
return elements.size() / 2;
}
}
Then we can define the collector that we need. This is essentially shorthand for collectingAndThen(toList(), PairList::new):
/**
* Returns a collector that collects to a pair list.
*
* #return the collector
*/
public static <E> Collector<E, ?, PairList<E>> toPairList() {
return Collectors.collectingAndThen(Collectors.toList(), PairList::new);
}
Note that it could be worthwhile defining a PairList constructor that doesn't defensively copy the list, for the use case that we know the backing list is freshly generated (as in this case). That's not really essential right now, though. But once we did that, this method would be collectingAndThen(toCollection(ArrayList::new), PairList::newNonDefensivelyCopiedPairList).
And now we can use it:
/**
* Creates a pair list with collectingAndThen, toList(), and PairList::new
*/
#Test
public void example() {
List<List<Integer>> intPairs = Stream.of(1, 2, 3, 4, 5, 6)
.collect(toPairList());
System.out.println(intPairs); // [[1, 2], [2, 3], [3, 4]]
List<List<String>> stringPairs = Stream.of("a", "b", "c", "d")
.collect(toPairList());
System.out.println(stringPairs); // [[a, b], [b, c]]
}
Here's a complete source file with a runnable example (as a JUnit test):
package ex;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Test;
public class PairCollectors {
/**
* A view on a list of its elements as pairs.
*
* #param <T> the element type
*/
static class PairList<T> extends AbstractList<List<T>> {
private final List<T> elements;
/**
* Creates a new pair list.
*
* #param elements the elements
*
* #throws NullPointerException if elements is null
* #throws IllegalArgumentException if the length of elements is not even
*/
public PairList(List<T> elements) {
Objects.requireNonNull(elements, "elements must not be null");
this.elements = new ArrayList<>(elements);
if (this.elements.size() % 2 != 0) {
throw new IllegalArgumentException("number of elements must have even size");
}
}
#Override
public List<T> get(int index) {
return Arrays.asList(elements.get(index), elements.get(index + 1));
}
#Override
public int size() {
return elements.size() / 2;
}
}
/**
* Returns a collector that collects to a pair list.
*
* #return the collector
*/
public static <E> Collector<E, ?, PairList<E>> toPairList() {
return Collectors.collectingAndThen(Collectors.toList(), PairList::new);
}
/**
* Creates a pair list with collectingAndThen, toList(), and PairList::new
*/
#Test
public void example() {
List<List<Integer>> intPairs = Stream.of(1, 2, 3, 4, 5, 6)
.collect(toPairList());
System.out.println(intPairs); // [[1, 2], [2, 3], [3, 4]]
List<List<String>> stringPairs = Stream.of("a", "b", "c", "d")
.collect(toPairList());
System.out.println(stringPairs); // [[a, b], [b, c]]
}
}
Assuming there is a Pair with left, right and getters and a constructor:
static class Paired<T> extends AbstractSpliterator<Pair<T>> {
private List<T> list = new ArrayList<>(2);
private final Iterator<T> iter;
public Paired(Iterator<T> iter) {
super(Long.MAX_VALUE, 0);
this.iter = iter;
}
#Override
public boolean tryAdvance(Consumer<? super Pair<T>> consumer) {
getBothIfPossible(iter);
if (list.size() == 2) {
consumer.accept(new Pair<>(list.remove(0), list.remove(0)));
return true;
}
return false;
}
private void getBothIfPossible(Iterator<T> iter) {
while (iter.hasNext() && list.size() < 2) {
list.add(iter.next());
}
}
}
Usage would be:
Iterator<Integer> iterator = List.of(1, 2, 3, 4, 5).iterator();
Paired<Integer> p = new Paired<>(iterator);
StreamSupport.stream(p, false)
.forEach(pair -> System.out.println(pair.getLeft() + " " + pair.getRight()));
I know I'm late to the party, but all of the answers seem to be really complicated or have a lot of GC overhead/short-lived objects (which is not a big deal with modern JVMs), but why not do it simply like this?
public class PairCollaterTest extends TestCase {
static class PairCollater<T> implements Function<T, Stream<Pair<T, T>>> {
T prev;
#Override
public Stream<Pair<T, T>> apply(T curr) {
if (prev == null) {
prev = curr;
return Stream.empty();
}
try {
return Stream.of(Pair.of(prev, curr));
} finally {
prev = null;
}
}
}
public void testPairCollater() {
Stream.of("0", "1", "2", "3", "4", "5").sequential().flatMap(new PairCollater<>()).forEach(System.out::println);
}
}
Prints:
(0,1)
(2,3)
(4,5)
Just replace IntStream.range(1, 101) with your stream (you don't need to know your stream's size) -
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
public class TestClass {
public static void main(String[] args) {
final Pair pair = new Pair();
final List<Pair> pairList = new ArrayList<>();
IntStream.range(1, 101)
.map(i -> {
if (pair.a == null) {
pair.a = i;
return 0;
} else {
pair.b = i;
return 1;
}
})
.filter(i -> i == 1)
.forEach(i -> {
pairList.add(new Pair(pair));
pair.reset();
});
pairList.stream().forEach(p -> System.out.print(p + " "));
}
static class Pair {
public Object a;
public Object b;
public Pair() {
}
public Pair(Pair orig) {
this.a = orig.a;
this.b = orig.b;
}
void reset() {
a = null;
b = null;
}
#Override
public String toString() {
return "{" + a + "," + b + '}';
}
}
}
I have to use a PushbackIterator which uses a pushback(E) method.
So if the value in aIter is less than the value in bIter, aIter is returned, while the value in bIter is put into the pushback(E) method, and vice versa.
If the original lists are
(1, 4, 5) and (2, 3, 6)
then the result list would be
(1, 2, 3, 4, 5, 6)
.
I believe that I need to determine if an iterator has no values left. So if bIter has no more elements, I get an element from aIter and add it to the result list.
How would I determine if an iterator has no more values?
public static<E extends Comparable<E>> List<E> mergeSortedLists(List<E> a, List<E> b) {
List<E> result = new ArrayList<E>();
PushbackIterator<E> aIter = new PushbackIterator<E>(a.iterator());
PushbackIterator<E> bIter = new PushbackIterator<E>(b.iterator());
while (aIter.hasNext() && bIter.hasNext()) {
if (aIter.next().compareTo(bIter.next()) < 0) {
result.add(aIter.next());
aIter.pushback(bIter.next());
}
if (aIter.next().compareTo(bIter.next()) > 0)
result.add(bIter.next());
bIter.pushback(aIter.next());
}
return result;
}
The while terminates if one of the iterators has no more elements, thus afterwards you can just add the remaining elements of the iterators:
while (aIter.hasNext()) {
result.add(aIter.next());
}
while (bIter.hasNext()) {
result.add(bIter.next());
}
Btw, your code has some flaws since you call .next() multiple times before adding an element. Because of this you will skip elements. Try this:
public static<E extends Comparable<E>> List<E> mergeSortedLists(List<E> a, List<E> b) {
List<E> result = new ArrayList<E>();
PushbackIterator<E> aIter = new PushbackIterator<E>(a.iterator());
PushbackIterator<E> bIter = new PushbackIterator<E>(b.iterator());
while (aIter.hasNext() && bIter.hasNext()) {
E aElem = aIter.next();
E bElem = bIter.next();
if (aElem.compareTo(bElem) <= 0) {
result.add(aElem);
bIter.pushback(bElem);
} else {
result.add(bElem);
aIter.pushback(aElem);
}
}
while (aIter.hasNext()) {
result.add(aIter.next());
}
while (bIter.hasNext()) {
result.add(bIter.next());
}
return result;
}
A binary search tree was created by traversing through an array from left to right and inserting each element. This tree may not be a balanced tree. Given a binary search tree with distinct elements, print all possible arrays that could have led to this tree.
To answer to this question I wrote the following code. Still, it seems that it doesn't print all possible arrays that could have lead to the the tree in all the cases. What do you think should be modified ?
public class Main {
public static LinkedList<Integer> passed = new LinkedList<>();
public static LinkedList<BinaryTree> notyet = new LinkedList<>();
public static ArrayList<LinkedList<Integer>> results = new ArrayList<LinkedList<Integer>>();
public static void main(String args[]) {
BinaryTree tr = readTree();
ArrayList<LinkedList<Integer>> result = allSequences(tr);
for (LinkedList<Integer> l : result){
for(int elem: l) System.out.print(elem+" ");
System.out.println("");
}
}
private static BinaryTree readTree() {
BinaryTree tr = new BinaryTree(2, null, null);
tr.left = new BinaryTree(1, null, null);
tr.right = new BinaryTree(3, null, null);
return tr;
}
public static ArrayList<LinkedList<Integer>> allSequences(BinaryTree tr){
// implement here
ArrayList<LinkedList<Integer>> result = new ArrayList<LinkedList<Integer>>();
findseqs(passed,notyet,tr);
//result=results.clone();
for(LinkedList<Integer> sample :results){
result.add(sample);
}
return result;
}
public static void findseqs(LinkedList<Integer> passed, LinkedList<BinaryTree> notyet, BinaryTree tr) {
passed.add(tr.value);
if (tr.left != null) notyet.add(tr.left);
if (tr.right != null) notyet.add(tr.right);
if (notyet.isEmpty()) {
results.add(passed);
}
for (BinaryTree elem: notyet) {
LinkedList<Integer> temp = (LinkedList<Integer>) passed.clone();
LinkedList<BinaryTree> ptemp = (LinkedList<BinaryTree>) notyet.clone();
ptemp.remove(elem);
findseqs(temp, ptemp, elem);
}
}
What holds about the array is that if A is ancestor of B in the graph then A precedes B in the array. Nothing else can be assumed.
So the arrays can be produced by the following recursive function.
function sourceArrays(Tree t)
// leafe node
if t == null
return empty list;
r = root(t);
append r to existing arrays;
la = sourceArrays(t.left);
ra = sourceArrays(t.right);
ac = createArrayCombitations(la, ra);
append ac to existing arrays;
end
function createArrayCombitations(la, ra)
foreach a in la
foreach b in ra
r = combineArrays(a,b);
add r to result;
end
end
end
function combineArrays(a, b)
generate all combinations of elements from two array such that order of elements in each array is preserved.
Ie if x precedes y in a or b the x precedes y in result
I need help to make a main method to test this program I've made for an assignment
Write a method to merge two linked lists of integers that are sorted into descending order. The result should be a third linked list that is the sorted combination of the original lists. Do not destroy the original lists.
import java.util.Iterator;
import java.util.LinkedList;
public class Exercise6
{
public static LinkedList<Integer> merge(LinkedList<Integer> a,LinkedList<Integer> b)
{
//Initialize variables
LinkedList<Integer> result = new LinkedList<Integer>();
Iterator<Integer> aI = a.iterator();
Iterator<Integer> bI = b.iterator();
int aTemp = 0;
int bTemp = 0;
//Get the first values from both lists using the next method
aTemp = aI.next();
bTemp = bI.next();
while(aI.hasNext() && bI.hasNext())
{
//Comparing the two elements
if(aTemp > bTemp)
{
result.add(bTemp);
bTemp = bI.next();
}
}
if(!aI.hasNext())
{
result.add(aTemp);
}
while(aI.hasNext())
{
result.add(aTemp);
aTemp = aI.next();
}
while(bI.hasNext())
{
result.add(bTemp);
bTemp = bI.next();
}
if(!aI.hasNext())
{
result.add(aTemp);
}
else
{
result.add(bTemp);
}
return result;
}
}
I think this is all you are asking for:
LinkedList<Integer> list1 = new LinkedList<Integer>();
list1.add(9);
list1.add(7);
list1.add(3);
LinkedList<Integer> list2 = new LinkedList<Integer>();
list1.add(8);
list1.add(5);
list1.add(1);
Exercise6 test = new Exercise6();
test.merge(list1,list2)
First, you are missing an else for your if in while(aI.hasNext() && bI.hasNext()). Next, I would strongly recommend you program to the List interface (instead of the concrete LinkedList type). Also, I would make the merge method generic on some comparable type T. Something like,
public static <T extends Comparable<? super T>> List<T> merge(List<T> a, List<T> b) {
// Initialize variables
List<T> result = new LinkedList<>();
Iterator<T> aI = a.iterator();
Iterator<T> bI = b.iterator();
// Get the first values from both lists using the next method
T aTemp = aI.hasNext() ? aI.next() : null;
T bTemp = bI.hasNext() ? bI.next() : null;
while (aI.hasNext() && bI.hasNext()) {
// Comparing the two elements
if (aTemp.compareTo(bTemp) < 0) {
result.add(bTemp); // <-- add the right-hand side
bTemp = bI.next();
} else {
result.add(aTemp); // <-- add the left-hand side
aTemp = aI.next();
}
}
// Add the final two values from the loop.
if (aTemp.compareTo(bTemp) < 0) {
result.add(bTemp);
result.add(aTemp);
} else {
result.add(aTemp);
result.add(bTemp);
}
while (aI.hasNext()) { // Add any remaining values from a
result.add(aI.next());
}
while (bI.hasNext()) { // Add any remaining values from b
result.add(bI.next());
}
return result;
}
Then you can test merge like
public static void main(String[] args) {
System.out.println(merge(Arrays.asList(6, 4, 2), Arrays.asList(5, 3, 1)));
System.out.println(merge(Arrays.asList("bat", "ant"),
Arrays.asList("dog", "cat")));
}
I get
[6, 5, 4, 3, 2, 1]
[dog, cat, bat, ant]
So do you write your code without ever testing it? I would suggest you get familiar with writing driver classes since as your code gets bigger you will need to test it along the way.
Create another class in the same package of your Exercise class: you can call it ExerciseDriver. Import classes as needed.
Declare Initialize and populate two linked lists. Declare a third linked lost to store the result.
Call the static method of your Exercise6 class
Print the result to verify
You could do something like:
import java.util.LinkedList;
public Class ExcerciseDriver{
public static void main (String[] args){
LinkedList<Integer> list1 = new LinkedList<>();
LinkedList<Integer> list2 = new LinkedList<>();
LinkedList<Integer> resultList;
list1.add(77);
list1.add(7);
list1.add(6);
list2.add(100);
list2.add(43);
list2.add(8);
resultList = Excercise6.merge(list1, list2);
System.out.println(resultList);
}
}
Now all you have to do is running the main method and verify the correctness of your algorithm
I'm trying to generalize the code to find all subsets of a given string(elements that are repeated will be treated as distinct) into one that would work for any list.
public class Subsets{
private static <T> void RecursiveSubsets(List<List<T>> list, ArrayList<T> soFar, List<T> rest)
{
if(rest.isEmpty())
{
list.add(soFar);
}
else
{
List<T> remaining;
if(rest.size() == 1)
{
remaining = new ArrayList<T>();
}
else
{
remaining = rest.subList(1, rest.size() - 1);
}
//include the element
ArrayList<T> includeFirst = new ArrayList<T>(soFar);
includeFirst.add(rest.get(0));
RecursiveSubsets(list, includeFirst, remaining);
//exclude the element
RecursiveSubsets(list, soFar, remaining);
}
}
public static <T> List<List<T>> getAllSubsets(List<T> set)
{
List<List<T>> subsets = new ArrayList<List<T>>();
RecursiveSubsets(subsets,new ArrayList<T>(),set);
return subsets;
}
public static void main(String [] args)
{
List<Integer> ints = new ArrayList<Integer>(){
{
add(0);add(1);add(2);add(3);
}
};
List<List<Integer>> allSubsets = getAllSubsets(ints);
System.out.println("Total Subsets returned : " + allSubsets.size());
for(int i=0; i<allSubsets.size(); ++i)
{
for(int j=0; j<allSubsets.get(i).size(); ++j)
{
System.out.print(allSubsets.get(i).get(j) + " ");
}
System.out.println();
}
}
}
After a few attempts I was able to get this to compile but this is what I get as output.
Even if I have more integers, it still returns this. I'm not able to figure out what I have missed and need help finding it.
$ java Subsets
Total Subsets returned : 4
0 1
0
1
Your program is actually almost correct, and you just have the sublist logic a bit wrong.
The javadoc for List.sublist says
Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive.
The word "exclusive" here is critical.
If you just change
remaining = rest.subList(1, rest.size() - 1);
to
remaining = rest.subList(1, rest.size());
your code works.
The logic of this (in pseudocode) is typically:
List<List<T>> subsets( List<T> list ){
if( list is empty ) return a list containing the empty list;
// else:
subsetsWithout = subsets( list w/o 0th element );
result.addAll(subsetsWithout);
for( subset in subsetsWithout )
result.add( subset + list[0] )
return result;
}
It looks like what you're doing is different, and the fact that you're trying to return things through the function parameters is making it more confusing.