Is there a fast way to generate the cartesian power of a set?
For example, if the set is {1, 2}, then {1, 2} x {1, 2} = {(1, 1), (1, 2), (2, 1), (2, 2)}. How would I go about generating it for any given power?
Thank you.
I guess with power, you mean how often the set is combined with itself? So power 3 would be:
{1, 2} x {1, 2} x {1, 2} = (({1, 2} x {1, 2}) x {1, 2})
so you can solve it recursively, combine the set once, and then the set with the result...
If you like, you can adapt my Iterator for Lists of Lists to List of Sets , and build an interator:
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 <Set <T>> llo) {
// transform Set<T> to List <T>, because we need an index later
List <List <T>> llt = new ArrayList <List <T>> ();
for (Set <T> st : llo)
{
List <T> lt = new ArrayList <T> ();
for (T t: st)
lt.add (t);
llt.add (lt);
}
lilio = llt;
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 <Set <T>> lilio;
public CartesianIterable (List <Set <T>> llo) {
lilio = llo;
}
public Iterator <List <T>> iterator () {
return new CartesianIterator <T> (lilio);
}
}
public class SetItTest
{
public static void main ( String [] args )
{
Set <Integer> si = new HashSet<Integer> ();
si.add (1);
si.add (2);
List <Set<Integer>> ls = new ArrayList <Set<Integer>> ();
ls.add (si);
ls.add (si);
ls.add (si);
CartesianIterable <Integer> ci = new CartesianIterable <Integer> (ls);
for (List <Integer> li : ci)
{
for (int i : li)
System.out.print (i + " ");
System.out.println ();
}
}
}
Output:
java SetItTest
1 1 1
2 1 1
1 2 1
2 2 1
1 1 2
2 1 2
1 2 2
2 2 2
If you can use external libraries, Guava has Sets.cartesianProduct(Set<E>...), so you can just do:
Set<Integer> set = ImmutableSet.of(1, 2);
Set<List<Integer>> = Sets.cartesianProduct(set, set);
// returns {[1, 1], [1, 2], [2, 1], [2, 2]} as desired
(Disclosure: I contribute to Guava.)
You can try with for two vectors v1 = {x1...xn}, v2 = {y1...yn}
public List producto(List a, List b) {
List producto = new ArrayList();
for (String s1 : a);
for (String s2 : b) {
List duo = new ArrayList();
duo.add(s1);
duo.add(s2);
producto.add(duo);
}
}
return producto;
}
Related
I am working on a problem to find which all combinations of integer in a given list can sum up to a given number.
public class SumProblem {
/*
* Input 2-2-3-7
* Output 2+2+3 and 7
*/
public static ArrayList<ArrayList<Integer>> find(ArrayList<Integer> input, int requiredSum) {
ArrayList<ArrayList<Integer>> result = new ArrayList<>();
find(result, requiredSum, 0, new ArrayList<>(), 0, input);
return result;
}
public static void find(ArrayList<ArrayList<Integer>> result , int requiredSum , int currentSum, ArrayList<Integer> partialResult, int i, ArrayList<Integer> input) {
if (currentSum == requiredSum ) {
ArrayList<Integer> temp = new ArrayList<>();
temp = (ArrayList<Integer>) partialResult.clone();
result.add(temp);
return;
}
if (i >= input.size()) {
return;
}
find(result, requiredSum, currentSum , partialResult, i +1, input );
partialResult.add(input.get(i));
find(result, requiredSum, currentSum + input.get(i) , partialResult, i +1, input );
}
public static void main(String[] args) {
ArrayList<Integer> input = new ArrayList<>();
input.add(2);
input.add(1);
input.add(3);
ArrayList<ArrayList<Integer>> output = find(input, 3);
System.out.println(output.toString());
}
}
I have written code below.
I am facing one problem. In the below line of code, it is adding up all the numbers i traverse even if i create new ArrayList object and assign it to partialResult.
partialResult.add(input.get(i));
Could anyone suggest the solution ?
You have two recursive calls in this dynamic programming solution to the problem. One is supposed to not include the current value in the result, the other does.
You need to make a defensive copy of partialResult, otherwise both recursive calls are going to have a reference to the same list. A list is a mutable object. If both calls get a reference to the same list object, then when you add something to it anywhere, both of them will see the modified list.
The easiest way to make a defensive copy of a list is just to write:
new ArrayList<>(partialResult)
Here is a working version of the program:
import java.util.*;
public class SumProblem {
public static List<List<Integer>> find(List<Integer> input, int requiredSum) {
List<List<Integer>> result = new ArrayList<>();
find(result, requiredSum, 0, new ArrayList<>(), 0, input);
return result;
}
public static void find(List<List<Integer>> result, int requiredSum, int currentSum,
List<Integer> partialResult, int i, List<Integer> input) {
if (currentSum == requiredSum) {
result.add(new ArrayList<>(partialResult)); // add a copy of the list
return;
}
if (i >= input.size()) {
return;
}
// make defensive copies in the recursive calls
find(result, requiredSum, currentSum, new ArrayList<>(partialResult), i + 1, input);
partialResult.add(input.get(i));
find(result, requiredSum, currentSum + input.get(i), new ArrayList<>(partialResult), i + 1, input);
}
public static void main(String[] args) {
List<Integer> input = List.of(2, 8, 2, 3, 4);
List<List<Integer>> output = find(input, 7);
System.out.println(output);
}
}
Output:
[[3, 4], [2, 2, 3]]
I've made a few other changes:
Use List<Integer> and List<List<Integer>> as the types (code to the interface)
Use List.of() to create the input list (added in Java 9)
Don't call toString() on objects passed to println — it's unneeded
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;
}
I want to something which is similar to the scala grouped function. Basically, pick 2 elements at a time and process them. Here is a reference for the same :
Split list into multiple lists with fixed number of elements
Lambdas do provide things like groupingBy and partitioningBy but none of them seem to do the same as the grouped function in Scala. Any pointers would be appreciated.
You can use Guava library.
List<Integer> bigList = ...
List<List<Integer>> smallerLists = Lists.partition(bigList, 10);
It sounds like a problem that is better handled like a low-level Stream operation just like the ops provided by the Stream API itself. A (relative) simple solution may look like:
public static <T> Stream<List<T>> chunked(Stream<T> s, int chunkSize) {
if(chunkSize<1) throw new IllegalArgumentException("chunkSize=="+chunkSize);
if(chunkSize==1) return s.map(Collections::singletonList);
Spliterator<T> src=s.spliterator();
long size=src.estimateSize();
if(size!=Long.MAX_VALUE) size=(size+chunkSize-1)/chunkSize;
int ch=src.characteristics();
ch&=Spliterator.SIZED|Spliterator.ORDERED|Spliterator.DISTINCT|Spliterator.IMMUTABLE;
ch|=Spliterator.NONNULL;
return StreamSupport.stream(new Spliterators.AbstractSpliterator<List<T>>(size, ch)
{
private List<T> current;
#Override
public boolean tryAdvance(Consumer<? super List<T>> action) {
if(current==null) current=new ArrayList<>(chunkSize);
while(current.size()<chunkSize && src.tryAdvance(current::add));
if(!current.isEmpty()) {
action.accept(current);
current=null;
return true;
}
return false;
}
}, s.isParallel());
}
Simple test:
chunked(Stream.of(1, 2, 3, 4, 5, 6, 7), 3)
.parallel().forEachOrdered(System.out::println);
The advantage is that you do not need a full collection of all items for subsequent stream processing, e.g.
chunked(
IntStream.range(0, 1000).mapToObj(i -> {
System.out.println("processing item "+i);
return i;
}), 2).anyMatch(list->list.toString().equals("[6, 7]")));
will print:
processing item 0
processing item 1
processing item 2
processing item 3
processing item 4
processing item 5
processing item 6
processing item 7
true
rather than processing a thousand items of IntStream.range(0, 1000). This also enables using infinite source Streams:
chunked(Stream.iterate(0, i->i+1), 2).anyMatch(list->list.toString().equals("[6, 7]")));
If you are interested in a fully materialized collection rather than applying subsequent Stream operations, you may simply use the following operation:
List<Integer> list=Arrays.asList(1, 2, 3, 4, 5, 6, 7);
int listSize=list.size(), chunkSize=2;
List<List<Integer>> list2=
IntStream.range(0, (listSize-1)/chunkSize+1)
.mapToObj(i->list.subList(i*=chunkSize,
listSize-chunkSize>=i? i+chunkSize: listSize))
.collect(Collectors.toList());
You can create your own collector. Something like this:
class GroupingCollector<T> implements Collector<T, List<List<T>>, List<List<T>>> {
private final int elementCountInGroup;
public GroupingCollector(int elementCountInGroup) {
this.elementCountInGroup = elementCountInGroup;
}
#Override
public Supplier<List<List<T>>> supplier() {
return ArrayList::new;
}
#Override
public BiConsumer<List<List<T>>, T> accumulator() {
return (lists, integer) -> {
if (!lists.isEmpty()) {
List<T> integers = lists.get(lists.size() - 1);
if (integers.size() < elementCountInGroup) {
integers.add(integer);
return;
}
}
List<T> list = new ArrayList<>();
list.add(integer);
lists.add(list);
};
}
#Override
public BinaryOperator<List<List<T>>> combiner() {
return (lists, lists2) -> {
List<List<T>> r = new ArrayList<>();
r.addAll(lists);
r.addAll(lists2);
return r;
};
}
#Override
public Function<List<List<T>>, List<List<T>>> finisher() {
return lists -> lists;
}
#Override
public Set<Characteristics> characteristics() {
return Collections.emptySet();
}
}
And then you can use it in a way like this:
List<List<Integer>> collect = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).collect(new GroupingCollector<>(3));
System.out.println(collect);
Will print:
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
A recursive solution to transform the list to a list-of-lists would also be possible
int chunkSize = 2;
private <T> List<List<T>> process(List<T> list) {
if (list.size() > chunkSize) {
List<T> chunk = list.subList(0, chunkSize);
List<T> rest = list.subList(chunkSize, list.size());
List<List<T>> lists = process(rest);
return concat(chunk, lists);
} else {
ArrayList<List<T>> retVal = new ArrayList<>();
retVal.add(list);
return retVal;
}
}
private <T> List<List<T>> concat(List<T> chunk, List<List<T>> rest) {
rest.add(0, chunk);
return rest;
}
You could write your own collector finisher, similar to
final List<String> strings = Arrays.asList("Hello", "World", "I", "Am", "You");
final int size = 3;
final List<List<String>> stringLists = strings.stream()
.collect(Collectors.collectingAndThen(Collectors.toList(), new Function<List<String>, List<List<String>>>() {
#Override
public List<List<String>> apply(List<String> strings) {
final List<List<String>> result = new ArrayList<>();
int counter = 0;
List<String> stringsToAdd = new ArrayList<>();
for (final String string : strings) {
if (counter == 0) {
result.add(stringsToAdd);
} else {
if (counter == size) {
stringsToAdd = new ArrayList<>();
result.add(stringsToAdd);
counter = 0;
}
}
++counter;
stringsToAdd.add(string);
}
return result;
}
}));
System.out.println("stringLists = " + stringLists); // stringLists = [[Hello, World, I], [Am, You]]
A simple version with java 8 streams api:
static <T> List<List<T>> partition(List<T> list, Integer partitionSize) {
int numberOfLists = BigDecimal.valueOf(list.size())
.divide(BigDecimal.valueOf(partitionSize), 0, CEILING)
.intValue();
return IntStream.range(0, numberOfLists)
.mapToObj(it -> list.subList(it * partitionSize, Math.min((it+1) * partitionSize, list.size())))
.collect(Collectors.toList());
}
Say I have several List<T>s, I will put them into another list or other collections, so I don't know how many list<T> I have until I call List<List<T>>.size()
Take below List<Integer> as an example:
list1=[1,2]
list2=[3,4]
list3=[5,6]
....
listn=[2*n-1,2n];
How can I get the result of list1*list2*list3*...listn as a Cartesian product?
For example:
list1*list2*list3
should be:
[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5],[2,3,6],[2,4,5],[2,4,6]
You can use recursion to achieve it, your base case of recursion is when input is empty then return empty list, else process the remaining elements. E.g.
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
public class CartesianProduct {
public static <T> List<List<T>> calculate(List<List<T>> input) {
List<List<T>> res = new ArrayList<>();
if (input.isEmpty()) { // if no more elements to process
res.add(new ArrayList<>()); // then add empty list and return
return res;
} else {
// we need to calculate the cartesian product
// of input and store it in res variable
process(input, res);
}
return res; // method completes , return result
}
private static <T> void process(List<List<T>> lists, List<List<T>> res) {
//take first element of the list
List<T> head = lists.get(0);
//invoke calculate on remaining element, here is recursion
List<List<T>> tail = calculate(lists.subList(1, lists.size()));
for (T h : head) { // for each head
for (List<T> t : tail) { //iterate over the tail
List<T> tmp = new ArrayList<>(t.size());
tmp.add(h); // add the head
tmp.addAll(t); // and current tail element
res.add(tmp);
}
}
}
public static void main(String[] args) {
//we invoke the calculate method
System.out.println(calculate(Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(3, 4),
Arrays.asList(5, 6))));
}
}
Output
[[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5],[2,3,6],[2,4,5],[2,4,6]]
Thanks to #sol4me 's answer using tail recursion, here is another version which is not using tail recursion but I think is easier to understand.
public class CartesianProduct {
public static <T> List<List<T>> calculate(List<List<T>> input) {
List<List<T>> result = new ArrayList<List<T>>();
if (input.isEmpty()) { // If input an empty list
// add empty list and return
result.add(new ArrayList<T>());
return result;
} else {
// get the first list as a head
List<T> head = input.get(0);
// recursion to calculate a tail list
List<List<T>> tail = calculate(input.subList(1, input.size()));
// we merge every head element with every tail list.
for (T h : head) {
for (List<T> t : tail) {
List<T> resultElement = new ArrayList<T>();
resultElement.add(h);
resultElement.addAll(t);
result.add(resultElement);
}
}
}
return result;
}
public static void main(String[] args) {
List<List<Integer>> bigList = Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(3, 4),
Arrays.asList(5, 6),
Arrays.asList(7, 8));
System.out.println(calculate(bigList));
}
}
The map-and-reduce approach using nested loops
Prepare a list of lists List<List<T>> populated with a single empty value. This list is used further as a storage of intermediate results and as a final result.
Sequentially append the data from incoming lists List<List<T>> to the intermediate result and obtain the final result. Schematically, this iterative process looks as follows:
result0: [[]]
list1: [1,2]
-------
result1: [[1],[2]]
list2: [3,4]
-------
result2: [[1,3],[1,4],[2,3],[2,4]]
list3: [5,6]
-------
result3: [[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5],[2,3,6],[2,4,5],[2,4,6]]
Try it online!
/**
* #param lists an arbitrary number of lists
* #param <T> the type of the elements
* #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();
// Cartesian product, intermediate result
List<List<T>> cp = Collections.singletonList(Collections.emptyList());
// iterate through incoming lists
for (List<T> list : lists) {
// non-null and non-empty lists
if (list == null || list.size() == 0) continue;
// intermediate result for next iteration
List<List<T>> next = new ArrayList<>();
// rows of current intermediate result
for (List<T> row : cp) {
// elements of current list
for (T el : list) {
// new row for next intermediate result
List<T> nRow = new ArrayList<>(row);
nRow.add(el);
next.add(nRow);
}
}
// pass to next iteration
cp = next;
}
// Cartesian product, final result
return cp;
}
public static void main(String[] args) {
List<List<Integer>> lists = prepareLists(3);
List<List<Integer>> cp = cartesianProduct(lists);
// output without spaces
System.out.println(lists.toString().replace(" ", ""));
System.out.println(cp.toString().replace(" ", ""));
}
// supplementary method, prepares lists for multiplication
public static List<List<Integer>> prepareLists(int n) {
List<List<Integer>> lists = new ArrayList<>(n);
for (int i = 1; i <= n; i++)
lists.add(Arrays.asList(i * 2 - 1, i * 2));
return lists;
}
Output:
[[1,2],[3,4],[5,6]]
[[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5],[2,3,6],[2,4,5],[2,4,6]]
See also: Generate all combinations from multiple lists
This is my first time working with linked lists and I've created both of my lists from two separate files and tokenized the data.
Now I need to compare the data and look for similarities, by that I mean the same data.
Such has list 1: 1, 3, dog and list 2: 1, dog, cat. Both have 1 and dog.
I am unsure how to approach this, and would love some tips, input, or hints.
The code which compares two Lists only in case when their elements are comparable (i.e. implements Comparable interface).
This is parametrized so you can provide any type of List element which implements Comparable (<T extends Comparable<T>>)
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ComparatorTest {
public static void main(String[] args) {
List<Integer> list1 = new ArrayList<>(Arrays.asList(new Integer[]{1, 2, 3, 6, 7}));
List<Integer> list2 = new ArrayList<>(Arrays.asList(new Integer[]{1, 2, 3, 6}));
final int result = new ComparatorTest().compareTo(list1, list2);
System.out.println("result = " + result);
}
<T extends Comparable<T>> int compareTo(List<T> list1, List<T> list2) {
int minLength = Math.min(list1.size(), list2.size());
for (int i = 0; i < minLength; i++) {
final int compareValue = list1.get(i).compareTo(list2.get(i));
if (compareValue != 0) {
return compareValue; // They are already not equal
}
}
if (list1.size() == list2.size()) {
return 0; // They are equal
} else if (list1.size() < list2.size()) {
return -1; // list 1 is smaller
} else {
return 1;
}
}
}