How do I generate a Cartesian product in Java? - java

I have a number of ArrayList with each ArrayList having objects and each one can have different length. I need to generate permutation like in the below example:
Suppose I have 2 ArrayList:
ArrayList A has object a, object b and object c
ArrayList B has object d, object e
Then the output should be 6 new ArrayList with these combinations:
Combination 1 object a and object d,
Combination 2 object a and object e,
Combination 3 object b and object d,
Combination 4 object b and object e,
Combination 5 object c and object d,
Combination 6 object c and object e,
Can anyone help me?

Guava 19+
Lists.cartesianProduct(List...)
E.g.:
List<Object> list1 = Arrays.asList("a", "b", "c");
List<Object> list2 = Arrays.asList("d", "e");
System.out.println(Lists.cartesianProduct(list1, list2));
Output:
[[a, d], [a, e], [b, d], [b, e], [c, d], [c, e]]

With Java8 streams
List<String> a = Arrays.asList("a", "b", "c");
List<String> b = Arrays.asList("d", "e");
String[][] AB = a.stream()
.flatMap(ai -> b.stream()
.map(bi -> new String[]{ai, bi}))
.toArray(String[][]::new);
System.out.println(Arrays.deepToString(AB));
output
[[a, d], [a, e], [b, d], [b, e], [c, d], [c, e]]
To get as List
List<List<String>> ll = a.stream()
.flatMap(ai -> b.stream()
.map(bi -> new ArrayList<>(Arrays.asList(ai, bi))))
.collect(Collectors.toList());

With an Iterable+Iterator:
import java.util.*;
class CartesianIterator <T> implements Iterator <List <T>> {
private final List <List <T>> lilio;
private int current = 0;
private final long last;
public CartesianIterator (final List <List <T>> llo) {
lilio = llo;
long product = 1L;
for (List <T> lio: lilio)
product *= lio.size ();
last = product;
}
public boolean hasNext () {
return current != last;
}
public List <T> next () {
++current;
return get (current - 1, lilio);
}
public void remove () {
++current;
}
private List<T> get (final int n, final List <List <T>> lili) {
switch (lili.size ())
{
case 0: return new ArrayList <T> (); // no break past return;
default: {
List <T> inner = lili.get (0);
List <T> lo = new ArrayList <T> ();
lo.add (inner.get (n % inner.size ()));
lo.addAll (get (n / inner.size (), lili.subList (1, lili.size ())));
return lo;
}
}
}
}
class CartesianIterable <T> implements Iterable <List <T>> {
private List <List <T>> lilio;
public CartesianIterable (List <List <T>> llo) {
lilio = llo;
}
public Iterator <List <T>> iterator () {
return new CartesianIterator <T> (lilio);
}
}
You can use them in a simplified for-loop:
class CartesianIteratorTest {
public static void main (String[] args) {
List <Character> la = Arrays.asList (new Character [] {'a', 'b', 'c'});
List <Character> lb = Arrays.asList (new Character [] {'d', 'e'});
List <List <Character>> llc = new ArrayList <List <Character>> ();
llc.add (la);
llc.add (lb);
CartesianIterable <Character> ci = new CartesianIterable <Character> (llc);
for (List<Character> lo: ci)
show (lo);
}
public static void show (List <Character> lo) {
System.out.print ("(");
for (Object o: lo)
System.out.print (o);
System.out.println (")");
}
}

Cartesian product of multiple lists using the map and reduce approach
The map method represents each element of the list as a singleton list and specifies the format of the result.
Intermediate output:
[[a], [b], [c]]
[[d], [e]]
[[f]]
The reduce method sums pairs of 2D lists into a single 2D list.
Final output:
[[a, d, f], [a, e, f], [b, d, f], [b, e, f], [c, d, f], [c, e, f]]
Try it online!
public static void main(String[] args) {
List<String> a = Arrays.asList("a", "b", "c");
List<String> b = Arrays.asList("d", "e");
List<String> c = Arrays.asList("f");
List<List<String>> cp = cartesianProduct(Arrays.asList(a, b, c));
// output
System.out.println(cp);
}
public static <T> List<List<T>> cartesianProduct(List<List<T>> lists) {
// check if not null
if (lists == null) return null;
// cartesian product of multiple lists
return lists.stream()
// only those lists that are not null and not empty
.filter(list -> list != null && list.size() > 0)
// represent each list element as a singleton list
.map(list -> list.stream().map(Collections::singletonList)
// Stream<List<List<T>>>
.collect(Collectors.toList()))
// intermediate output
.peek(System.out::println)
// stream of lists into a single list
.reduce((lst1, lst2) -> lst1.stream()
// combinations of inner lists
.flatMap(inner1 -> lst2.stream()
// concatenate into a single list
.map(inner2 -> Stream.of(inner1, inner2)
.flatMap(List::stream)
.collect(Collectors.toList())))
// list of combinations
.collect(Collectors.toList()))
// otherwise an empty list
.orElse(Collections.emptyList());
}
See also: Cartesian product of an arbitrary number of sets

Use Guava... Here is an example of a Cartesian product of a list with itself:
public static void main(String[] args) {
//How to do a cartesian product of a List of items
List<Integer> listToSelfMultiply = Arrays.asList(
new Integer(1), new Integer(2), new Integer(3), new Integer(4));
LinkedList<Integer> linkedListCopy = Lists.newLinkedList(listToSelfMultiply);
for (Integer i : listToSelfMultiply) {
if (linkedListCopy.size() == 1) {
break;
}
linkedListCopy.remove();
System.out.println("" + Arrays.deepToString(
Lists.cartesianProduct(Arrays.asList(i), linkedListCopy).toArray()) + "");
}
}

Use nested for loops that would have a loop for every ArrayList as below. I am assuming I have two ArrayLists - intList and stringList. I can have two nested for loops (one for each list) to generate the permutation.
for (Integer i : intList) {
for (String s : stringList) {
...
}
}

Cartesian product of multiple lists
You can use the reduce method with three parameters:
identity - specify the result stub.
List<List<T>>
accumulator - append elements of lists to the result.
List<List<T>> result, List<T> list
combiner - is used in parallel mode, combines the results.
List<List<T>> result1, List<List<T>> result2
Try it online!
/**
* #param lists the lists for multiplication
* #param <T> the type of list element
* #return the Cartesian product
*/
public static <T> List<List<T>> cartesianProduct(List<List<T>> lists) {
// check if incoming data is not null
if (lists == null) return Collections.emptyList();
return lists.stream()
// non-null and non-empty lists
.filter(list -> list != null && list.size() > 0)
// stream of lists into a single list
.reduce(// identity - specify the result stub
Collections.singletonList(Collections.emptyList()),
// accumulator - append elements of lists to the result
(result, list) -> result.stream()
.flatMap(inner -> list.stream()
.map(el -> {
List<T> nList = new ArrayList<>(inner);
nList.add(el);
return nList;
}))
// list of combinations
.collect(Collectors.toList()),
// combiner - is used in parallel mode, combines the results
(result1, result2) -> {
result1.addAll(result2);
return result1;
});
}
public static void main(String[] args) {
List<String> l1 = Arrays.asList("A", "B");
List<String> l2 = Arrays.asList("C", "D");
List<String> l3 = Arrays.asList("E", "F");
List<List<String>> cp = cartesianProduct(Arrays.asList(l1, l2, l3));
// output
System.out.println(cp);
}
Output:
[[A,C,E],[A,C,F],[A,D,E],[A,D,F],[B,C,E],[B,C,F],[B,D,E],[B,D,F]]
See also: Cartesian product of 3 collections

Related

Java 8 - Merge All Subsets Containing Common Elements

Starting with a set of sets "groups":
Set<Set<String>> groups = new HashSet<>();
I want to create a new list of sets by merging all subsets with common elements:
i.e. Starting with the sets below:
A = {a, b, c}
B = {c, d, e, f}
C = {f, g, h, i, j}
D = {k, l, m}
E = {m, n, o}
F = {p, q, r}
The final result would be:
Set 1 = {a, b, c, d, e, f, g, h, i, j}
Set 2 = {k, l, m, n, o}
Set 3 = {p, q, r}
Any advice on how to accomplish this would be appreciated.
EDIT: In case of uneven sets it would perform the same. So if it were a method, it pseudo would look like this:
public void doStuff(){
Set<Set<String>> groups = {{a,b,c}, {c,d,e,f}, {m, n, o}}
Set<Set<String>> newGroups = mergeSubsets(groups);
System.out.println(newGroups);
}
public Set<Set<String>> mergeSubsets(Set<Set<String>> groups){
//some operations
}
Console out:
New Groups: {{a,b,c,d,e,f}, {m, n, o}}
You can just implement the algorithm as you describe it in your problem statement -- find intersecting sets and merge them until there is nothing to merge. Standard library has a method Collections.disjoint that helps by determining if two collections have any elements in common:
// this implementation sacrifices efficiency for clarity
public Set<Set<String>> mergeSubsets(Set<Set<String>> groups) {
Set<Set<String>> result = new HashSet<>();
for (Set<String> set : groups) {
// try to find a set in result that intersects this set
// if one is found, merge the two. otherwise, add this set to result
result.stream()
.filter(x -> !Collections.disjoint(x, set))
.findAny()
.ifPresentOrElse( // this method was added in java 9
x -> x.addAll(set),
() -> result.add(new HashSet<>(set))
);
}
// if nothing got merged we are done; otherwise, recurse and try again
return result.size() == groups.size() ? result : mergeSubsets(result);
}
Here is the imperative way based on #NiksVij solution. Obviously the solution of #NiksVij is not correct and this answer aims to fix this and extend a bit more:
public class MergeSet {
public static void main(String... args) {
List<Set<String>> list = new ArrayList<>();
String[] A = {"a", "c", "e", "g"};
String[] B = {"b", "d", "f", "h"};
String[] C = {"c", "e", "f"};
String[] D = {"b"};
list.add(new HashSet<>(Arrays.asList(A)));
list.add(new HashSet<>(Arrays.asList(C)));
list.add(new HashSet<>(Arrays.asList(B)));
list.add(new HashSet<>(Arrays.asList(D)));
List<Set<String>> newGroups = merge(list);
System.out.println(newGroups);
}
#SuppressWarnings("empty-statement")
private static <T> List<Set<T>> merge(List<Set<T>> list) {
if (list == null || list.isEmpty()) {
return list;
}
List<Set<T>> merged = new ArrayList<>();
do {
merged.add(list.get(0));
list.remove(0);
while (mergeStep(merged.get(merged.size() - 1), list));
} while (!list.isEmpty());
return merged;
}
private static <T> boolean mergeStep(Set<T> setToCheck, List<Set<T>> remainingList) {
boolean atLeastOnceMerged = false;
Iterator<Set<T>> iterator = remainingList.iterator();
while (iterator.hasNext()) {
Set<T> elements = iterator.next();
boolean doMerge = !Collections.disjoint(elements, setToCheck);
if (doMerge) {
atLeastOnceMerged |= doMerge;
setToCheck.addAll(elements);
iterator.remove();
}
}
return atLeastOnceMerged;
}
import java.util.*;
public class MergeSet {
public static void main(String... args) {
List<Set<String>> groups = new ArrayList<>();
String[] A = {"a", "b", "c"};
String[] B = {"c", "d", "e", "f"};
String[] C = {"f", "g", "h", "i", "j"};
String[] D = {"k", "l", "m"};
String[] E = {"m", "n", "o"};
String[] F = {"p", "q", "r"};
groups.add(new HashSet<>(Arrays.asList(A)));
groups.add(new HashSet<>(Arrays.asList(B)));
groups.add(new HashSet<>(Arrays.asList(C)));
groups.add(new HashSet<>(Arrays.asList(D)));
groups.add(new HashSet<>(Arrays.asList(E)));
groups.add(new HashSet<>(Arrays.asList(F)));
Set<Set<String>> newGroups = mergeSubsets(groups);
System.out.println(newGroups);
}
private static Set<Set<String>> mergeSubsets(List<Set<String>> groups) {
List<Set<String>> newGroups = new ArrayList<>();
Set<String> init = groups.get(0);
groups.remove(0);
newGroups.add(init);
while (!groups.isEmpty()) {
removeMergedElementFromGroupAndUpdateNewGroup(newGroups.get(newGroups.size() - 1), groups);
if(!groups.isEmpty()) {
init = groups.get(0);
groups.remove(0);
newGroups.add(init);
}
}
return new HashSet<>(newGroups);
}
private static void removeMergedElementFromGroupAndUpdateNewGroup(Set<String> master2, List<Set<String>> masterList) {
Iterator<Set<String>> iterator = masterList.iterator();
while (iterator.hasNext()) {
Set<String> strings = iterator.next();
boolean merge = strings.stream().anyMatch(string -> master2.contains(string));
if (merge) {
master2.addAll(strings);
iterator.remove();
}
}
}
}
Hope this helps instead of Set<Set<String>> groups I have used List<Set<String>> groups for the ease of using lists if you have a constraint of using Set only , you can generate List from Set(say yourSet) by passing it into the constructor of Lists implementation , for eg.
groups = new ArrayList<>(yourSet);

How to interleave (merge) two Java 8 Streams?

Stream<String> a = Stream.of("one", "three", "five");
Stream<String> b = Stream.of("two", "four", "six");
What do I need to do for the output to be the below?
// one
// two
// three
// four
// five
// six
I looked into concat but as the javadoc explains, it just appends one after the other, it does not interleave / intersperse.
Stream<String> out = Stream.concat(a, b);
out.forEach(System.out::println);
Creates a lazily concatenated stream whose elements are all the
elements of the first stream followed by all the elements of the
second stream.
Wrongly gives
// one
// three
// five
// two
// four
// six
Could do it if I collected them and iterated, but was hoping for something more Java8-y, Streamy :-)
Note
I don't want to zip the streams
“zip” operation will take an element from each collection and combine them.
the result of a zip operation would be something like this: (unwanted)
// onetwo
// threefour
// fivesix
I’d use something like this:
public static <T> Stream<T> interleave(Stream<? extends T> a, Stream<? extends T> b) {
Spliterator<? extends T> spA = a.spliterator(), spB = b.spliterator();
long s = spA.estimateSize() + spB.estimateSize();
if(s < 0) s = Long.MAX_VALUE;
int ch = spA.characteristics() & spB.characteristics()
& (Spliterator.NONNULL|Spliterator.SIZED);
ch |= Spliterator.ORDERED;
return StreamSupport.stream(new Spliterators.AbstractSpliterator<T>(s, ch) {
Spliterator<? extends T> sp1 = spA, sp2 = spB;
#Override
public boolean tryAdvance(Consumer<? super T> action) {
Spliterator<? extends T> sp = sp1;
if(sp.tryAdvance(action)) {
sp1 = sp2;
sp2 = sp;
return true;
}
return sp2.tryAdvance(action);
}
}, false);
}
It retains the characteristics of the input streams as far as possible, which allows certain optimizations (e.g. for count()and toArray()). Further, it adds the ORDERED even when the input streams might be unordered, to reflect the interleaving.
When one stream has more elements than the other, the remaining elements will appear at the end.
A much dumber solution than Holger did, but may be it would fit your requirements:
private static <T> Stream<T> interleave(Stream<T> left, Stream<T> right) {
Spliterator<T> splLeft = left.spliterator();
Spliterator<T> splRight = right.spliterator();
T[] single = (T[]) new Object[1];
Stream.Builder<T> builder = Stream.builder();
while (splRight.tryAdvance(x -> single[0] = x) && splLeft.tryAdvance(builder)) {
builder.add(single[0]);
}
return builder.build();
}
As you can see from the question comments, I gave this a go using zip:
Stream<String> a = Stream.of("one", "three", "five");
Stream<String> b = Stream.of("two", "four", "six");
Stream<String> out = interleave(a, b);
public static <T> Stream<T> interleave(Stream<T> streamA, Stream<T> streamB) {
return zip(streamA, streamB, (o1, o2) -> Stream.of(o1, o2)).flatMap(s -> s);
}
/**
* https://stackoverflow.com/questions/17640754/zipping-streams-using-jdk8-with-lambda-java-util-stream-streams-zip
**/
private static <A, B, C> Stream<C> zip(Stream<A> streamA, Stream<B> streamB, BiFunction<A, B, C> zipper) {
final Iterator<A> iteratorA = streamA.iterator();
final Iterator<B> iteratorB = streamB.iterator();
final Iterator<C> iteratorC = new Iterator<C>() {
#Override
public boolean hasNext() {
return iteratorA.hasNext() && iteratorB.hasNext();
}
#Override
public C next() {
return zipper.apply(iteratorA.next(), iteratorB.next());
}
};
final boolean parallel = streamA.isParallel() || streamB.isParallel();
return iteratorToFiniteStream(iteratorC, parallel);
}
private static <T> Stream<T> iteratorToFiniteStream(Iterator<T> iterator, boolean parallel) {
final Iterable<T> iterable = () -> iterator;
return StreamSupport.stream(iterable.spliterator(), parallel);
}
This may not be a good answer because
(1) it collects to map, which you don't want to do I guess and
(2) it is not completely stateless as it uses AtomicIntegers.
Still adding it because
(1) it is readable and
(2) community can get an idea from this and try to improve it.
Stream<String> a = Stream.of("one", "three", "five");
Stream<String> b = Stream.of("two", "four", "six");
AtomicInteger i = new AtomicInteger(0);
AtomicInteger j = new AtomicInteger(1);
Stream.of(a.collect(Collectors.toMap(o -> i.addAndGet(2), Function.identity())),
b.collect(Collectors.toMap(o -> j.addAndGet(2), Function.identity())))
.flatMap(m -> m.entrySet().stream())
.sorted(Comparator.comparing(Map.Entry::getKey))
.forEach(e -> System.out.println(e.getValue())); // or collect
Output
one
two
three
four
five
six
#Holger's edit
Stream.concat(a.map(o -> new AbstractMap.SimpleEntry<>(i.addAndGet(2), o)),
b.map(o -> new AbstractMap.SimpleEntry<>(j.addAndGet(2), o)))
.sorted(Map.Entry.comparingByKey())
.forEach(e -> System.out.println(e.getValue())); // or collect
without any external lib (using jdk11)
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class MergeUtil {
private static <T> Stream<T> zipped(List<T> lista, List<T> listb) {
int maxSize = Math.max(lista.size(), listb.size());
final var listStream = IntStream
.range(0, maxSize)
.mapToObj(i -> {
List<T> result = new ArrayList<>(2);
if (i < lista.size()) result.add(lista.get(i));
if (i < listb.size()) result.add(listb.get(i));
return result;
});
return listStream.flatMap(List::stream);
}
public static void main(String[] args) {
var l1 = List.of(1, 2, 3);
var l2 = List.of(4, 5, 6, 7, 8, 9);
final var zip = zipped(l1, l2);
System.out.println(zip.collect(Collectors.toList()));
}
}
listStream is a Stream<List<A>> that flatted in return.
The result is:
[1, 4, 2, 5, 3, 6, 7, 8, 9]
One solution with Iterator
final Iterator<String> iterA = a.iterator();
final Iterator<String> iterB = b.iterator();
final Iterator<String> iter = new Iterator<String>() {
private final AtomicInteger idx = new AtomicInteger();
#Override
public boolean hasNext() {
return iterA.hasNext() || iterB.hasNext();
}
#Override
public String next() {
return idx.getAndIncrement() % 2 == 0 && iterA.hasNext() ? iterA.next() : iterB.next();
}
};
// Create target Stream with StreamEx from: https://github.com/amaembo/streamex
StreamEx.of(iter).forEach(System.out::println);
// Or Streams from Google Guava
Streams.stream(iter).forEach(System.out::println);
Or simply by the solution in abacus-common provided by me:
AtomicInteger idx = new AtomicInteger();
StreamEx.merge(a, b, (s1, s2) -> idx.getAndIncrement() % 2 == 0 ? Nth.FIRST : Nth.SECOND).forEach(Fn.println());
Using Guava's Streams.zip and Stream.flatMap:
Stream<String> interleaved = Streams
.zip(a, b, (x, y) -> Stream.of(x, y))
.flatMap(Function.identity());
interleaved.forEach(System.out::println);
Prints:
one
two
three
four
five
six

Java collection pack() method

What would be a good way to implement the pack() operation of a collection using Java stream? Here is what I'd like to accomplish:
List<String> items = Arrays.asList("A", "A", "B", "B", "A", "C", "C", "A", "A", "A");
List<List<String>> packs = items.stream().pack();
// packs: [[A,A],[B,B],[A],[C,C],[A,A,A]]
Alternatively, the pack operation could return a list of tuples in the form of (index, element, count):
[(0, A, 2), (2, B, 2), (4, A, 1), (5, C, 2), (7, A, 3)]
Currently I implemented this using a mutable accumulator in the following fashion:
Packer<String> packer = new Packer<>();
items.stream().forEach(packer);
List<Triple<Integer, T, Integer>> packs = packer.get();
public class Packer<T> implements Consumer<T>, Supplier<List<Triple<Integer, T, Integer>>>
{
private List<Triple<Integer, T, AtomicInteger>> result = new ArrayList<>();
private Optional<Triple<Integer, T, AtomicInteger>> currentElement = Optional.empty();
private int count = 0;
#Override
public void accept(T t)
{
if (currentElement.isPresent() && currentElement.get().getMiddle().equals(t))
{
currentElement.get().getRight().incrementAndGet();
}
else
{
currentElement = Optional.of(Triple.of(count, t, new AtomicInteger(1)));
result.add(currentElement.get());
}
count++;
}
#Override
public List<Triple<Integer, T, Integer>> get()
{
return result.stream().map(x -> Triple.of(x.getLeft(), x.getMiddle(), x.getRight().get())).collect(Collectors.toList());
}
}
You can collapse adjacent elements with StreamEx:
List<List<String>> packs = StreamEx.of(items)
.collapse(Object::equals, Collectors.toList())
.collect(Collectors.toList());
Output:
[[A, A], [B, B], [A], [C, C], [A, A, A]]
JDoodle Demo
I'm not sure if StreamEx supports collapsing with indexes.
Try this.
List<String> items = Arrays.asList("A", "A", "B", "B", "A", "C", "C", "A", "A", "A");
List<List<String>> result = items.stream()
.collect(() -> new LinkedList<List<String>>(),
(list, e) -> {
if (list.isEmpty() || !list.getLast().contains(e))
list.add(new LinkedList<>());
list.getLast().add(e);
},
(a, b) -> {});
System.out.println(result);
result
[[A, A], [B, B], [A], [C, C], [A, A, A]]
This can not be processed with parallel stream.
As #shmosel mentioned in his answer, it can done by StreamEx
List<List<String>> packs = StreamEx.of(items).collapse(Object::equals, Collectors.toList()).toList();
System.out.println(packs);
// [[A, A], [B, B], [A], [C, C], [A, A, A]]
MutableInt idx = MutableInt.of(0);
List<Triple<Integer, String, Integer>> packs2 = StreamEx.of(items).collapse(Object::equals, Collectors.toList())
.map(l -> Triple.of(idx.getAndAdd(l.size()), l.get(0), l.size())).toList();
System.out.println(packs2);
// [[0, A, 2], [2, B, 2], [4, A, 1], [5, C, 2], [7, A, 3]]
[Update]: Just found out, actually there are even simpler APIs available in StreamEx for this OP:
packs = StreamEx.of(items).groupRuns(Object::equals).toList();
System.out.println(packs);
packs2 = StreamEx.of(items).runLengths().mapKeyValue((k, v) -> Triple.of(idx.getAndAdd(v.intValue()), k, v.intValue())).toList();
System.out.println(packs2);
Amazing!
Seems like you could create a custom collector for that:
static class PackCollector<T> implements Collector<T, List<List<T>>, List<List<T>>> {
#Override
public Supplier<List<List<T>>> supplier() {
return () -> {
List<List<T>> list = new ArrayList<>();
list.add(new ArrayList<>());
return list;
};
}
#Override
public BiConsumer<List<List<T>>, T> accumulator() {
return (list, s) -> {
int size = list.size();
List<T> inner = list.get(size - 1);
int innerSize = inner.size();
if (innerSize > 0) {
T last = inner.get(inner.size() - 1);
if (s.equals(last)) {
inner.add(s);
} else {
List<T> newList = new ArrayList<>();
newList.add(s);
list.add(newList);
}
} else {
inner.add(s);
}
};
}
#Override
public BinaryOperator<List<List<T>>> combiner() {
return (left, right) -> {
List<T> lastLeft = left.get(left.size() - 1);
List<T> firstRight = right.get(0);
T leftElem = lastLeft.get(lastLeft.size() - 1);
T rightElem = firstRight.get(firstRight.size() - 1);
if (leftElem.equals(rightElem)) {
lastLeft.addAll(right.remove(0));
}
left.addAll(right);
return left;
};
}
#Override
public Set<Characteristics> characteristics() {
return EnumSet.of(Characteristics.IDENTITY_FINISH);
}
#Override
public Function<List<List<T>>, List<List<T>>> finisher() {
return Function.identity();
}
}
And then use it:
List<List<String>> result = items.stream().parallel().collect(new PackCollector<>());
System.out.println(result);

How to cross join multiple Lists in Java? [duplicate]

This question already has answers here:
Get a list of combinations of lists' elements
(4 answers)
Closed 8 years ago.
Cross Join concept is the same as database cross join. I have multiple lists lets say 3 to start with and I have to join the lists as below:
List<E> l1: {a, b},
List<E> l2: {c, d},
List<E> l3: {e, f},
Cross join should produce:
List<E> l4 = {a, c, f},
List<E> l5 = {a, c, e},
List<E> l6 = {a, d, f},
List<E> l7 = {a, d, e},
List<E> l8 = {b, c, f},
List<E> l9 = {b, c, e},
List<E> l10 = {b, d, f},
List<E> l11= {b, d, e};
3 Lists with 3 elements each will give 27 new lists. And number of elements in each list is same, always.
Now one possible solution is to iterate with three for loops and then add to 3 new lists.
Is there any other possible way to achieve this so that complexity is lower?
Thanks
This code will work for any List<List<T>> parameter.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class X {
public static void main(String[] args) {
List<List<String>> param = new ArrayList<List<String>>() {{
add(Arrays.asList("A", "B"));
add(Arrays.asList("C", "D"));
add(Arrays.asList("E", "F"));
}};
for (List<String> l : getCross(param)) {
System.out.println(l);
}
}
public static <T> List<List<T>> getCross(List<List<T>> values) {
List<List<T>> accumulator = new ArrayList<List<T>>();
if (values.size() != 0) {
List<T> comb = new ArrayList<T>();
comb.addAll(Collections.<T>nCopies(values.size(), null));
getCross(accumulator, 0, comb, values);
}
return accumulator;
}
private static <T> void getCross(List<List<T>> accumulator, int idx, List<T> combination, List<List<T>> param) {
if (idx == combination.size()) {
accumulator.add(new ArrayList<T>(combination));
} else {
for(T t : param.get(idx)) {
combination.set(idx, t);
getCross(accumulator, idx + 1, combination, param);
}
}
}
}
Below code will work for any kind of metric.
static void joinList()
{
List l11 = new ArrayList();
List l22 = new ArrayList();
List l33 = new ArrayList();
l11.add("a");
l11.add("b");
l22.add("c");
l22.add("d");
l33.add("e");
l33.add("f");
List<List> crosslist = new ArrayList<List>();
for(int i =0;i<l11.size();i++)
{
for(int j=0 ; j<l22.size();j++)
{
for(int k =0; k<l33.size();k++)
{
List list = new ArrayList();
list.add(l11.get(i));
list.add(l22.get(j));
list.add(l33.get(k));
crosslist.add(list);
}
}
}
}
try my solution,
you can use here as much as you need lists.
public class Main{
private void run() {
List<String> l11 = new ArrayList<String>(){{add("a");add("b");}};
List<String> l22 = new ArrayList<String>(){{add("c");add("d");}};
List<String> l33 = new ArrayList<String>(){{add("e");add("f");}};
crossJoin(l11, l22, l33);
}
public void crossJoin(List<String> ... lists) {
for (List<String> list : lists) {
mixList(list, lists);
}
}
private void mixList(List<String> list, List<String>[] lists) {
for (List<String> listSrt : lists) {
if (listSrt == list) continue;
for (String baseString : list) {
System.out.print(baseString + " ");
for (String outerStr : listSrt ) {
System.out.print(outerStr + " ");
}
System.out.println(" ");
}
}
}
public static void main(String[] args) {
Main main = new Main();
main.run();
}
}

How to sort multi-dimensional arrays start from a given Index

I try to sort only a selected part of an array.
I have try this code:
public static void shortArray(String[][] array){
Arrays.sort(array, new Comparator<String[]>() {
#Override
public int compare(final String[] entry1, final String[] entry2) {
final float time1 = Float.parseFloat(entry1[1]);
final float time2 = Float.parseFloat(entry2[1]);
if (time2 > time1) {
return 1;
} else if (time2 == time1) {
return 0;
} else {
return -1;
}
}
});
}
but it sorts the entire array.
Is there any way to sort starting from a specific index?
Yes, by creating a list-view of the array (through Arrays.asList), and by using list.subList and Collections.sort to sort a part of it.
String[][] arr = {{"5.0","a"},{"3.0","b"},{"2.0","c"},{"4.0","d"},{"1.0","e"}};
// Sort elements in range 2 ... arr.length
List<String[]> sublist = Arrays.asList(arr).subList(2, arr.length);
Collections.sort(sublist, new Comparator<String[]>() {
#Override
public int compare(String[] a1, String[] a2) {
return Float.valueOf(a1[0]).compareTo(Float.valueOf(a2[0]));
}
});
// Prints [[5.0, a], [3.0, b], [1.0, e], [2.0, c], [4.0, d]]
// ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
// not affected sorted by first index
System.out.println(Arrays.deepToString(arr));
Take the sublist from the main list, starting from particular index(that you need). Then use
Collections.sort(sublist)
Hope that helps.

Categories