Merging 4 sorted Arrays into one - java

I have this method to merge 2 sorted arrays into one sorted array:
public void merge(T[] a, int l1, int r1, T[] b, int l2, int r2, T[] c, int l3) {
while (l1 < r1 && l2 < r2) {
if (a[l1].compareTo(b[l2]) < 0) {
c[l3++] = a[l1++];
} else
c[l3++] = b[l2++];
}
while (l1 < r1)
c[l3++] = a[l1++];
while (l2 < r2)
c[l3++] = b[l2++];
}
But now I want to do it with 4 arrays at once.
I tried really long to come up with a solution, but wasn’t really successful. Does somebody have an idea how to do it?

There is a much simpler way using Java8 streams than doing this by hand:
combine all arrays into one stream (i've used 2 but you can use as many as you want to):
int[] arr1 = {1, 7, 10};
int[] arr2 = {1, 2, 4, 9};
Stream<int[]> ints = Stream.of(arr1, arr2);
then flatMap and sort them in a stream:
IntStream intStream = ints.flatMapToInt(Arrays::stream).sorted();
and when you print them you will see all the numbers sorted:
intStream.forEach(System.out::println);
1
1
2
4
7
9
10
combined in a function, it could look something like this:
public int[] merge(int[]... arrays) {
return Stream.of(arrays)
.flatMapToInt(Arrays::stream)
.sorted()
.toArray();
}
EDIT: The advantage of streams is, that you can further modify the values as you like. e.g. by leveraging the distinct function you can easily remove duplicates:
intStream = intStream.distinct();
intStream.forEach(System.out::println);
1
2
4
7
9
10

I've generalized the problem to "merging N sorted arrays into a single sorted array".
The code provided in the question utilizes generics. But it introduces a problem because arrays are not type-safe. In short, there's a substantial difference in their behavior: arrays are covariant and, on the other hand, generics are invariant. Due to that, compiler will not be abler to identify a problem when generics and arrays are mixed. It's a good practice to avoid usage of generic arrays.
Also, I've taken into account that it is clearly an algorithmic problem (therefore its audience broader than readers who have a deep insight in Java, which is required to grasp generic-based implementation) I've decided to create two flavors of solution one using arrays exclusively, another with generics and Collections framework.
Non-generic version
Below is the description of how to merge an arbitrary number of sorted arrays of primitives:
find the total number of elements and create a resulting array based on it;
define an array that will maintain a current position in each of the source arrays;
using a nested for loop for each position in the resulting array, pick the lowest value of all currently accessible values.
The time complexity of this algorithm is O(n * m) (where n - is the total number of elements in all arrays and m is the number of arrays).
The implementation might look like this:
public static int[] mergeNSorted(int[]... arrays) {
int[] result = new int[getTotalLength(arrays)];
int[] positions = new int[arrays.length]; // position for each array
for (int pos = 0; pos < result.length; pos++) {
int minCurVal = Integer.MAX_VALUE;
int curArr = 0;
for (int i = 0; i < arrays.length; i++) {
if (positions[i] < arrays[i].length && arrays[i][positions[i]] < minCurVal) {
minCurVal = arrays[i][positions[i]];
curArr = i;
}
}
result[pos] = minCurVal;
positions[curArr]++;
}
return result;
}
public static int getTotalLength(int[][] arrays) {
long totalLen = 0;
for (int[] arr : arrays) totalLen += arr.length;
if (totalLen > Integer.MAX_VALUE) throw new IllegalArgumentException("total length exceeded Integer.MAX_VALUE");
return (int) totalLen;
}
main() - demo
public static void main(String[] args) {
int[][] input =
{{1, 3}, {}, {2, 6, 7}, {10}, {4, 5, 8, 9}};
System.out.println(Arrays.toString(mergeNSorted(input)));
}
Output
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Generic version
In this version, input considered to be a list containing multiple lists of generic type T which expected to implement Comparable interface.
This solution enhances the array-based implementation provided above, reducing the overall time complexity to O(n * log m) (where n - is the total number of elements in all arrays and m is the number of arrays).
Instead of performing m iteration for each resulting element it maintains a PriorityQueue, which in this case represents a Min-Heap (i.e. when a head element is being retrieved from it, it'll have the lowest value of all the elements that are present in the queue).
Every element in queue wraps the value of a particular element retrieved from one of the given lists, as well the data regarding the source of this value (i.e. an index of the list and a position inside this list).
This wrapper over the element of the nested list can be represented by the class shown below.
public class ElementWrapper<V extends Comparable<V>> implements Comparable<ElementWrapper<V>> {
private V value;
private int listIndex;
private int position;
public ElementWrapper(V value, int listIndex, int position) {
this.value = value;
this.listIndex = listIndex;
this.position = position;
}
// getters
#Override
public int compareTo(ElementWrapper<V> o) {
return value.compareTo(o.getValue());
}
}
Note, that this class implements the of Comparable interface based on the value of wrapped list element.
The queue is being prepopulated with the first element of each non-empty list. And then until the queue is not empty, its lowest element is being removed and gets added to the resulting list. Also, if a list to which the latest element retrieved from the queue points, has more elements, the next of them will be added into the queue.
Note that both operations of adding a new element into the priority queue add() and removing its head element remove() according to the documentation has a cost of O(n) time (where n is the number of elements in the queue).
The same time complexity can be achieved by utilizing a TreeSet instead, but in practice PriorityQueue will perform better because a heap is easier to maintain than a red-black tree.
The code might look like this:
public static <T extends Comparable<T>> List<T> mergeNSorted(List<List<T>> lists) {
List<T> result = new ArrayList<>();
Queue<ElementWrapper<T>> queue = getInitializedQueue(lists);
while (!queue.isEmpty()) {
ElementWrapper<T> next = queue.remove();
result.add(next.getValue());
if (next.getPosition() + 1 < lists.get(next.getListIndex()).size()) {
queue.add(new ElementWrapper<>(lists.get(next.getListIndex()).get(next.getPosition() + 1),
next.getListIndex(),
next.getPosition() + 1));
}
}
return result;
}
public static <T extends Comparable<T>> Queue<ElementWrapper<T>> getInitializedQueue(List<List<T>> lists) {
Queue<ElementWrapper<T>> queue = new PriorityQueue<>();
for (int i = 0; i < lists.size(); i++) {
if (lists.get(i).isEmpty()) continue;
queue.add(new ElementWrapper<>(lists.get(i).get(0), i, 0));
}
return queue;
}
main() - demo
public static void main(String[] args) {
List<List<Integer>> genericInput =
List.of(List.of(1, 3), List.of(), List.of(2, 6, 7), List.of(10), List.of(4, 5, 8, 9));
System.out.println(mergeNSorted(genericInput));
}
Output
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

I'm not a Java programmer so I'll just give Pythonesque pseudo-code.
First turn each non-emptyarray into a triplet:
(next_value, index, array)
Now put those into a priority queue sorted by next value.
while 0 < queue.size():
(next_value, index, array) = queue.poll()
answer.append(next_value)
if index+1 < array.length:
queue.add((array[index+1], index+1, array))
If you have k arrays, this will take O(log(k)) comparisons per element produced.
Sadly, Java does not seem to have anything corresponding to the swaptop method. I practice if one array has a run of values, using .peek() to get the top element then .swaptop(...) if you can will let you go through those runs with O(1) work per element.

This could also be an good example using List<String> in addition to int[]
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class TestClass {
public static List<String> list(String... elems) {
return new ArrayList<>(Arrays.asList(elems));
}
public static List<String> mergedListSorted(List<String>... listsVarArgs) {
return Stream.of(listsVarArgs).flatMap(List::stream).sorted().collect(Collectors.toList());
}
#Test
public void sortedListsTest() {
// Sorted sub lists
List<String> AGMS = list("A", "G", "M", "S");
List<String> BHNT = list("B", "H", "N", "T");
List<String> CIOU = list("C", "I", "O", "U");
List<String> DJPV = list("D", "J", "P", "V");
List<String> EKQW = list("E", "K", "Q", "W");
List<String> FLRX = list("F", "L", "R", "X");
System.out.println(mergedListSorted(AGMS, BHNT, CIOU, DJPV, EKQW, FLRX));
System.out.println(mergedListSorted(BHNT, BHNT, CIOU, BHNT));
}
}
The according output of two examples:
[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X]
[B, B, B, C, H, H, H, I, N, N, N, O, T, T, T, U]

Related

Conversion of int array to ArrayList

I have a function that gets an array of primitive data (int), I need to return the array of two elements the smallest and the largest number. If length of the array is 1 then just return two first elements int the array. I came up with such solution:
public static int[] minMax(int[] arr) {
if (arr.length==1)
return new int[]{arr[0],arr[0]} ;// return if arr is 1 element
else {
ArrayList<Integer> ar = new ArrayList<Integer>();
//?
return new int[]{Collections.max(ar),Collections.min(ar)};
}
}
But how do I convert an array to an ArrayList? Is there a more efficient way maybe?
By calling Collections.min and Collections.max, you're iterating over the array twice. You can cut this time down by streaming the array and letting it do the heavy lifting, as James Mudd suggested. However, note that by doing so you'd be wasting time on calculating the sum and accumulating the count of the elements, which you don't care about. It may be more efficient to calculated these yourself:
public static int[] minMax(int[] arr) {
// Assuming arr has at least one element
int min = arr[0];
int max = arr[0];
for (int i = 1; i < arr.length; ++i) {
int curr = arr[i];
if (curr < min) {
min = curr;
} else if (curr > max) {
max = curr;
}
}
return new int[]{min, max};
}
You could use IntSummaryStatistics the method would look like
public static int[] minMax(int[] arr) {
IntSummaryStatistics intSummaryStatistics = Arrays.stream(arr).summaryStatistics();
return new int[] {intSummaryStatistics.getMin(), intSummaryStatistics.getMax()};
}
Here's another way of solving this task with streams.
Instead, using IntSummuryStatistics we can provide an array of two elements as a container of the resulting values while applying collect and manually define to accumulate stream elements in it.
public static int[] minMax(int[] sourceArr) {
if (sourceArr.length == 0) throw new IllegalArgumentException(); // source array is empty
return Arrays.stream(sourceArr)
.collect(
() -> new int[]{sourceArr[0], sourceArr[0]}, // mutable container
(arr, next) -> { // accumulator - populating the container with elements of the stream
arr[0] = Math.min(arr[0], next);
arr[1] = Math.max(arr[1], next);
},
(left, right) -> { // combiner - merging containers in parallel
left[0] = Math.min(left[0], right[0]);
left[1] = Math.max(left[1], right[1]);
});
}
main()
public static int[] minMax(int[] sourceArr) {
System.out.println(Arrays.toString(minMax(new int[]{3, 5, -3, 8, 9})));
System.out.println(Arrays.toString(minMax(new int[]{3, -1, 3, 12, 27})));
}
Output:
[-3, 9]
[-1, 27]
But how do I convert an array to an ArrayList?
It's not possible to convert an array of primitives into a List directly. When you have an array of reference type (like Integer, BigDecimal, etc.) you can use Arrays.asList() to fixed-size list wrapped around the given array. But it wouldn't work with primitive arrays.
In order to translate int[] into a List<Integer> you have to create a new list and populate it with the contents of the array.
So your actual goal is to obtain the result as a list, the code provided above might be changed like that:
public static List<Integer> minMax(int[] sourceArr) {
if (sourceArr.length == 0) throw new IllegalArgumentException(); // source array is empty
return Arrays.stream(sourceArr)
.collect(
() -> Arrays.asList(sourceArr[0], sourceArr[0]), // mutable container
(list, next) -> { // accumulator - populating the container with elements of the stream
list.set(0, Math.min(list.get(0), next));
list.set(1, Math.max(list.get(1), next));
},
(left, right) -> { // combiner - merging containers in parallel
left.set(0, Math.min(left.get(0), right.get(0)));
left.set(1, Math.max(left.get(1), right.get(1)));
});
}

sort the elements in java using priority queue

I want to sort the elements using Priority Queue in Java.
Here is my code. What is wrong in it?
import java.io.*;
import java.util.*;
class PQ {
static class IntCompare implements Comparator<Integer>{
#Override
public int compare(Integer arg0, Integer arg1) {
if(arg0 > arg1)
return -1;
else if(arg0 < arg1)
return 1;
else
return 0;
}
}
public static void main (String[] args) {
int a[] = { 1, 3, 8, 5, 2, 6 };
Comparator<Integer> c = new IntCompare();
PriorityQueue<Integer> pq=new PriorityQueue<>(c);
for(int i = 0; i < a.length; i++)
pq.add(a[i]);
System.out.println(pq);
}
}
my output is:
8, 5, 6, 1, 2, 3
correct output:
8, 6, 5, 3, 2, 1
When you call System.out.println(pq), the toString method is called implicitly.
The toString method of PriorityQueue extends from AbstractCollection, which
Returns a string representation of this collection. The string
representation consists of a list of the collection's elements in the
order they are returned by its iterator, enclosed in square brackets
("[]").
While the iterator of PriorityQueue is not guaranteed to traverse in particular order:
The Iterator provided in method iterator() is not guaranteed to
traverse the elements of the priority queue in any particular order.
since the queue is based on heap.
You can poll elements one by one to get ordered elements:
while (pq.size() != 0) {
System.out.print(pq.poll() + ","); // 8,6,5,3,2,1,
}
You should poll() all the elements until the queue is empty and save them somewhere to get them ordered.
Try the following, list contains items in sorted order. The priority key by itself not maintain the elements in sorted order, it just keeps the top element as minimum or maximum based on your implementation of the PQ.
public static void main (String[] args) {
int a[]={1,3,8,5,2,6};
Comparator<Integer> c = new IntCompare();
PriorityQueue<Integer> pq=new PriorityQueue<>(c);
for(int i=0;i<a.length;i++)
pq.add(a[i]);
ArrayList<Integer> list = new ArrayList<>();
while(!pq.isEmpty()){
list.add(pq.poll());
}
for(Integer i : list)
System.out.println(i);
}

Index an array by an array in java

In R you can do something like this:
> x = c(1, 222, 333, 4, 5)
> x[c(2, 3)]
[1] 222 333
> in the beginning of line is just a prompt in an interactive session. x is a vector of numeric values, and if you want the 2nd and 3rd element of x, you pass another vector c(2, 3) to index x. This is different from Arrays.copyOfRange in java: you can pass an arbitrary index vector to x, not necessarily in a continuous range, i.e. x[c(1,3,5)]
I am wondering if there is a similar feature in java.
As I understood your question, you could create a method that take a list of indexes as parameters.
For generic arrays, you'll need to use Array.newInstance and cast the resulting array to T[] (thanks and kudos for #Radiodef for pointing this out)
//for lists
static <T> List<T> buildList(List<T> original, int... indexes){
List<T> finalList = new ArrayList<>();
for(int index : indexes){
finalList.add(original.get(index));
}
return finalList;
}
//for arrays
static <T> T[] buildArray (T[] original, int... indexes){
#SuppressWarnings("unchecked")
T[] finalArray = (T[])Array.newInstance(original.getClass().getComponentType(), indexes.length);
for(int i = 0; i < indexes.length; i++){
finalArray[i] = original[indexes[i]];
}
return finalArray;
}
Few notes :
For primitive arrays (like int[] or double[]), you'll have to overload the methods, that's why I suggest you to use a List with generics instead.
Indexes for arrays in Java are 0 based (starts from 0 to length-1)
Don't forget to add additional checks for the method (valid index, original list or index not null)
If you use a LinkedList instead of an ArrayList, be aware that #get(int index) is an O(n) operation instead of O(1)
Example of usage :
public static void main(String[] args) {
Integer[] xArray = {-1, 10, 24, 7};
List<Integer> xList = Arrays.asList(-1, 10, 24, 7);
System.out.println(Arrays.toString(buildArray(xArray, 0, 2)));
System.out.println(buildList(xList, 0, 1, 3));
}
Which outputs:
[-1, 24]
[-1, 10, 7]
take a look at Arrays.copyOfRange

Convert HashMap of integers into unique integer array? [duplicate]

Do you know some neat Java libaries that allow you to make cartesian product of two (or more) sets?
For example: I have three sets. One with objects of class Person, second with objects of class Gift and third with objects of class GiftExtension.
I want to generate one set containing all possible triples Person-Gift-GiftExtension.
The number of sets might vary so I cannot do this in nested foreach loop.
Under some conditions my application needs to make a product of Person-Gift pair, sometimes it is triple Person-Gift-GiftExtension, sometimes there might even be sets Person-Gift-GiftExtension-GiftSecondExtension-GiftThirdExtension, etc.
Edit: Previous solutions for two sets removed. See edit history for details.
Here is a way to do it recursively for an arbitrary number of sets:
public static Set<Set<Object>> cartesianProduct(Set<?>... sets) {
if (sets.length < 2)
throw new IllegalArgumentException(
"Can't have a product of fewer than two sets (got " +
sets.length + ")");
return _cartesianProduct(0, sets);
}
private static Set<Set<Object>> _cartesianProduct(int index, Set<?>... sets) {
Set<Set<Object>> ret = new HashSet<Set<Object>>();
if (index == sets.length) {
ret.add(new HashSet<Object>());
} else {
for (Object obj : sets[index]) {
for (Set<Object> set : _cartesianProduct(index+1, sets)) {
set.add(obj);
ret.add(set);
}
}
}
return ret;
}
Note that it is impossible to keep any generic type information with the returned sets. If you knew in advance how many sets you wanted to take the product of, you could define a generic tuple to hold that many elements (for instance Triple<A, B, C>), but there is no way to have an arbitrary number of generic parameters in Java.
This is a pretty old question, but why not use Guava's cartesianProduct?
The method below creates the cartesian product of a list of list of strings:
protected <T> List<List<T>> cartesianProduct(List<List<T>> lists) {
List<List<T>> resultLists = new ArrayList<List<T>>();
if (lists.size() == 0) {
resultLists.add(new ArrayList<T>());
return resultLists;
} else {
List<T> firstList = lists.get(0);
List<List<T>> remainingLists = cartesianProduct(lists.subList(1, lists.size()));
for (T condition : firstList) {
for (List<T> remainingList : remainingLists) {
ArrayList<T> resultList = new ArrayList<T>();
resultList.add(condition);
resultList.addAll(remainingList);
resultLists.add(resultList);
}
}
}
return resultLists;
}
Example:
System.out.println(cartesianProduct(Arrays.asList(Arrays.asList("Apple", "Banana"), Arrays.asList("Red", "Green", "Blue"))));
would yield this:
[[Apple, Red], [Apple, Green], [Apple, Blue], [Banana, Red], [Banana, Green], [Banana, Blue]]
The number of sets might vary so I
cannot do this in nested foreach loop.
Two hints:
A x B x C = A x (B x C)
Recursion
Index-based solution
Working with the indices is an alternative that is fast and memory-efficient and can handle any number of sets. Implementing Iterable allows easy use in a for-each loop. See the #main method for a usage example.
public class CartesianProduct implements Iterable<int[]>, Iterator<int[]> {
private final int[] _lengths;
private final int[] _indices;
private boolean _hasNext = true;
public CartesianProduct(int[] lengths) {
_lengths = lengths;
_indices = new int[lengths.length];
}
public boolean hasNext() {
return _hasNext;
}
public int[] next() {
int[] result = Arrays.copyOf(_indices, _indices.length);
for (int i = _indices.length - 1; i >= 0; i--) {
if (_indices[i] == _lengths[i] - 1) {
_indices[i] = 0;
if (i == 0) {
_hasNext = false;
}
} else {
_indices[i]++;
break;
}
}
return result;
}
public Iterator<int[]> iterator() {
return this;
}
public void remove() {
throw new UnsupportedOperationException();
}
/**
* Usage example. Prints out
*
* <pre>
* [0, 0, 0] a, NANOSECONDS, 1
* [0, 0, 1] a, NANOSECONDS, 2
* [0, 0, 2] a, NANOSECONDS, 3
* [0, 0, 3] a, NANOSECONDS, 4
* [0, 1, 0] a, MICROSECONDS, 1
* [0, 1, 1] a, MICROSECONDS, 2
* [0, 1, 2] a, MICROSECONDS, 3
* [0, 1, 3] a, MICROSECONDS, 4
* [0, 2, 0] a, MILLISECONDS, 1
* [0, 2, 1] a, MILLISECONDS, 2
* [0, 2, 2] a, MILLISECONDS, 3
* [0, 2, 3] a, MILLISECONDS, 4
* [0, 3, 0] a, SECONDS, 1
* [0, 3, 1] a, SECONDS, 2
* [0, 3, 2] a, SECONDS, 3
* [0, 3, 3] a, SECONDS, 4
* [0, 4, 0] a, MINUTES, 1
* [0, 4, 1] a, MINUTES, 2
* ...
* </pre>
*/
public static void main(String[] args) {
String[] list1 = { "a", "b", "c", };
TimeUnit[] list2 = TimeUnit.values();
int[] list3 = new int[] { 1, 2, 3, 4 };
int[] lengths = new int[] { list1.length, list2.length, list3.length };
for (int[] indices : new CartesianProduct(lengths)) {
System.out.println(Arrays.toString(indices) //
+ " " + list1[indices[0]] //
+ ", " + list2[indices[1]] //
+ ", " + list3[indices[2]]);
}
}
}
Here is an Iterable, which allows you to use a simplified for-loop:
import java.util.*;
// let's begin with the demo. Instead of Person and Gift,
// I use the well known char and int.
class CartesianIteratorTest {
public static void main (String[] args) {
List <Object> lc = Arrays.asList (new Object [] {'A', 'B', 'C', 'D'});
List <Object> lC = Arrays.asList (new Object [] {'a', 'b', 'c'});
List <Object> li = Arrays.asList (new Object [] {1, 2, 3, 4});
// sometimes, a generic solution like List <List <String>>
// might be possible to use - typically, a mixture of types is
// the common nominator
List <List <Object>> llo = new ArrayList <List <Object>> ();
llo.add (lc);
llo.add (lC);
llo.add (li);
// Preparing the List of Lists is some work, but then ...
CartesianIterable <Object> ci = new CartesianIterable <Object> (llo);
for (List <Object> lo: ci)
show (lo);
}
public static void show (List <Object> lo) {
System.out.print ("(");
for (Object o: lo)
System.out.print (o + ", ");
System.out.println (")");
}
}
How is it done? We need an Iterable, to use the simplified for-loop, and an Iterator has to be returned from the Iterable.
We return a List of Objects - this could be a Set instead of List, but Set has no indexed access, so it would be a bit more complicated, to implement it with Set instead of List. Instead of a generic solution, Object would have been fine for many purposes, but generics allow for more restrictions.
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;
}
}
}
}
The mathematical work is done in the 'get'-method. Think about 2 sets of 10 elements. You have a total of 100 combinations, enumerated from 00, 01, 02, ... 10, ... to 99. For 5 X 10 elements 50, for 2 X 3 elements 6 combinations. The modulo of the sublist size helps to pick one element for each iteration.
Iterable i the least interesting thing here:
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);
}
}
To implement Iterable, which allows the for-each kind of loop, we have to implement iterator (), and for Iterator we have to implement hasNext (), next () and remove ().
Result:
(A, a, 1, )
(B, a, 1, )
(C, a, 1, )
(D, a, 1, )
(A, b, 1, )
(B, b, 1, )
(C, b, 1, )
(D, b, 1, )
...
(A, a, 2, )
...
(C, c, 4, )
(D, c, 4, )
Here is an Iterator that gives the cartesian product of a two-dimensional array, where the arrays components represent the sets from the question (one can always convert actual Sets to arrays):
public class CartesianIterator<T> implements Iterator<T[]> {
private final T[][] sets;
private final IntFunction<T[]> arrayConstructor;
private int count = 0;
private T[] next = null;
public CartesianIterator(T[][] sets, IntFunction<T[]> arrayConstructor) {
Objects.requireNonNull(sets);
Objects.requireNonNull(arrayConstructor);
this.sets = copySets(sets);
this.arrayConstructor = arrayConstructor;
}
private static <T> T[][] copySets(T[][] sets) {
// If any of the arrays are empty, then the entire iterator is empty.
// This prevents division by zero in `hasNext`.
for (T[] set : sets) {
if (set.length == 0) {
return Arrays.copyOf(sets, 0);
}
}
return sets.clone();
}
#Override
public boolean hasNext() {
if (next != null) {
return true;
}
int tmp = count;
T[] value = arrayConstructor.apply(sets.length);
for (int i = 0; i < value.length; i++) {
T[] set = sets[i];
int radix = set.length;
int index = tmp % radix;
value[i] = set[index];
tmp /= radix;
}
if (tmp != 0) {
// Overflow.
return false;
}
next = value;
count++;
return true;
}
#Override
public T[] next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
T[] tmp = next;
next = null;
return tmp;
}
}
The basic idea is to treat count as a multi-radix number (digit i has its own radix which equals the length of the i'th "set"). Whenever we have to resolve next (that is, when hasNext() is called and next is null), we decompose the number into its digits in this multi-radix. These digits are now used as the indices from which we draw elements from the different sets.
Example use:
String[] a = { "a", "b", "c"};
String[] b = { "X" };
String[] c = { "r", "s" };
String[][] abc = { a, b, c };
Iterable<String[]> it = () -> new CartesianIterator<>(abc, String[]::new);
for (String[] s : it) {
System.out.println(Arrays.toString(s));
}
Output:
[a, X, r]
[b, X, r]
[c, X, r]
[a, X, s]
[b, X, s]
[c, X, s]
If one doesn't like arrays, the code is trivially convertible into using collections.
I guess this is more or less similar to the answer given by "user unknown", only without recursion and collections.
You can get the Cartesian product of an arbitrary number of sets of different types and store it into a set of sets of objects Set<Set<Object>> using Java 9 Streams as follows:
Try it online!
public static Set<Set<Object>> cartesianProduct(Set<?>... sets) {
// incorrect incoming data
if (sets == null) return Collections.emptySet();
return Arrays.stream(sets)
// non-null and non-empty sets
.filter(set -> set != null && set.size() > 0)
// represent each set element as Set<Object>
.map(set -> set.stream().map(Set::<Object>of)
// Stream<Set<Set<Object>>>
.collect(Collectors.toSet()))
// summation of pairs of inner sets
.reduce((set1, set2) -> set1.stream()
// combinations of inner sets
.flatMap(inner1 -> set2.stream()
// merge two inner sets into one
.map(inner2 -> Stream.of(inner1, inner2)
.flatMap(Set::stream)
.collect(Collectors.toCollection(
LinkedHashSet::new))))
// set of combinations
.collect(Collectors.toCollection(LinkedHashSet::new)))
// returns Set<Set<Object>>, otherwise an empty set
.orElse(Collections.emptySet());
}
public static void main(String[] args) {
Set<Integer> set1 = Set.of(1, 2, 3);
Set<String> set2 = Set.of("A", "B", "C");
Set<Object> set3 = Set.of(new Time(0));
Set<Set<Object>> sets = cartesianProduct(set1, set2, set3);
// output
sets.forEach(System.out::println);
}
Output:
[1, A, 03:00:00]
[1, B, 03:00:00]
[1, C, 03:00:00]
[2, A, 03:00:00]
[2, B, 03:00:00]
[2, C, 03:00:00]
[3, A, 03:00:00]
[3, B, 03:00:00]
[3, C, 03:00:00]
See also: How to create a data structure similar to the cartesian product of three lists of different types?
Yes, there is Functional Java.
For a set s:
s.bind(P.p2(), s);
a simple solution, for example, for Integer set should be as follows:
void printCombination(List<Set<Integer>> listSet, Set<Integer> combination) {
if (listSet.isEmpty()) {
System.out.println("a combination :" + combination);
return;
}
Set<Integer> intSet = listSet.get(0);
for (Integer it : intSet) {
Set<Integer> combination1 = new HashSet<Integer>();
combination1.addAll(combination);
combination1.add(it);
List<Set<Integer>> listSet1 = new ArrayList<Set<Integer>>();
listSet1.addAll(listSet);
listSet1.remove(0);
this.printCombination(listSet1, combination1);
}
}
You can apply a simple generator interferace named Seq via this library. Unlike Guava's cartesianProduct, the sets/lists/iterables do not need to be within the same generic type bound B, all types are welcome. And all you need to do is writing the product as normal nested for-loops.
public static void main(String[] args) {
List<String> ls1 = Arrays.asList("a", "b");
List<Integer> ls2 = Arrays.asList(1, 2);
List<Character> ls3 = Arrays.asList('x', 'y');
Seq<String> seq = c -> {
for (String s : ls1) {
for (Integer i : ls2) {
for (Character d : ls3) {
c.accept(s + i + d);
}
}
}
};
System.out.println(seq.toSet());
}
The result would be
[a2x, a1y, b1x, b2y, a1x, a2y, b2x, b1y]

How to find the permutation of a sort in Java

I want to sort an array and find the index of each element in the sorted order.
So for instance if I run this on the array:
[3,2,4]
I'd get:
[1,0,2]
Is there an easy way to do this in Java?
Let's assume your elements are stored in an array.
final int[] arr = // elements you want
List<Integer> indices = new ArrayList<Integer>(arr.length);
for (int i = 0; i < arr.length; i++) {
indices.add(i);
}
Comparator<Integer> comparator = new Comparator<Integer>() {
public int compare(Integer i, Integer j) {
return Integer.compare(arr[i], arr[j]);
}
}
Collections.sort(indices, comparator);
Now indices contains the indices of the array, in their sorted order. You can convert that back to an int[] with a straightforward enough for loop.
import java.util.*;
public class Testing{
public static void main(String[] args){
int[] arr = {3, 2, 4, 6, 5};
TreeMap map = new TreeMap();
for(int i = 0; i < arr.length; i++){
map.put(arr[i], i);
}
System.out.println(Arrays.toString(map.values().toArray()));
}
}
One way to achieve this is to make a list of pairs with the starting index as the second part of the pair. Sort the list of pairs lexicographically, then read off the starting positions from the sorted array.
Starting array:
[3,2,4]
Add pairs with starting indexes:
[(3,0), (2,1), (4,2)]
Sort it lexicographically
[(2,1), (3,0), (4,2)]
then read off the second part of each pair
[1,0,2]
import java.io.*;
public class Sample {
public static void main(String[] args) {
int[] data = {0, 3, 2, 4, 6, 5, 10};//case:range 0 - 10
int i, rangeHigh = 10;
int [] rank = new int[rangeHigh + 1];
//counting sort
for(i=0; i< data.length ;++i) ++rank[data[i]];
for(i=1; i< rank.length;++i) rank[i] += rank[i-1];
for(i=0;i<data.length;++i)
System.out.print((rank[data[i]]-1) + " ");//0 2 1 3 5 4 6
}
}
As an update, this is relatively easy to do in Java 8 using the streams API.
public static int[] sortedPermutation(final int[] items) {
return IntStream.range(0, items.length)
.mapToObj(value -> Integer.valueOf(value))
.sorted((i1, i2) -> Integer.compare(items[i1], items[i2]))
.mapToInt(value -> value.intValue())
.toArray();
}
It somewhat unfortunately requires a boxing and unboxing step for the indices, as there is no .sorted(IntComparator) method on IntStream, or even an IntComparator functional interface for that matter.
To generalize to a List of Comparable objects is pretty straightforward:
public static <K extends Comparable <? super K>> int[] sortedPermutation(final List<K> items) {
return IntStream.range(0, items.size())
.mapToObj(value -> Integer.valueOf(value))
.sorted((i1, i2) -> items.get(i1).compareTo(items.get(i2)))
.mapToInt(value -> value.intValue())
.toArray();
}

Categories