Java
Cartesian Product
Programming
Algorithms
Code Implementation

How to create cartesian product over arbitrary groups of numbers in Java?

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Sure, let's delve into the concept and execution of creating the Cartesian product of arbitrary groups of numbers in Java. This will involve understanding how Cartesian products work, implementing them, and discussing some of their applications.

Introduction

The Cartesian product of multiple sets is a mathematical operation that returns a set of all possible tuples formed by picking an element from each input set. In programming, particularly in Java, understanding how to calculate a Cartesian product can be extremely useful, especially in scenarios such as configuration generation, combinatorial testing, or when dealing with multi-dimensional spaces.

Cartesian Product Explained

Given two sets, A and B, the Cartesian product, denoted as A×BA \times B, is the set of all ordered pairs (a, b), where aAa \in A and bBb \in B. For instance, if $A = \{1, 2\}$ and $B = \{x, y\}$, the Cartesian product A×BA \times B would be (1,x),(1,y),(2,x),(2,y){(1, x), (1, y), (2, x), (2, y)}.

For more than two sets, say AA, BB, and CC, this can be extended to A×B×CA \times B \times C, forming triplets (a, b, c) with aAa \in A, bBb \in B, and cCc \in C.

Java Implementation

To implement this in Java, we need to consider a recursive approach to handle the dynamic number of sets. The objective is to create a list of tuples, where each tuple is a product element.

Step-by-Step Implementation

  1. Input Preparation: We will first prepare our input as a list of lists. Each inner list will represent a set.
  2. Recursive Combination: A recursive method will build up combinations by iterating over the current set and combining each element with the combinations of the remainder.
  3. Base and Recursive Case: The base case will handle when only one set remains, and the recursive case will handle the expansion of the current set with the results of the recursive call.

Here's how you can achieve this in Java:

java
1import java.util.ArrayList;
2import java.util.List;
3
4public class CartesianProduct {
5    public static void main(String[] args) {
6        List<List<Integer>> input = new ArrayList<>();
7        input.add(List.of(1, 2));
8        input.add(List.of(3, 4));
9        input.add(List.of(5, 6));
10
11        List<List<Integer>> result = cartesianProduct(input);
12
13        for (List<Integer> tuple : result) {
14            System.out.println(tuple);
15        }
16    }
17
18    public static List<List<Integer>> cartesianProduct(List<List<Integer>> lists) {
19        List<List<Integer>> result = new ArrayList<>();
20        if (lists == null || lists.size() == 0) {
21            return result;
22        }
23        recurse(lists, result, new ArrayList<>(), 0);
24        return result;
25    }
26
27    private static void recurse(List<List<Integer>> lists, List<List<Integer>> result, List<Integer> current, int depth) {
28        if (depth == lists.size()) {
29            result.add(new ArrayList<>(current));
30            return;
31        }
32
33        for (Integer element : lists.get(depth)) {
34            current.add(element);
35            recurse(lists, result, current, depth + 1);
36            current.remove(current.size() - 1);
37        }
38    }
39}

Explanation

  • Base Case: Once the recursion reaches the depth equal to the number of input lists, the current combination (list) is added to the result.
  • Recursive Case: At each depth, we iterate over the elements of the current set (list at the current depth). We add an element to the current combination, then proceed deeper into the recursion. After returning from the recursive call, we backtrack by removing the last element and try the next element.

Key Points Summary

ConceptExplanation
Cartesian ProductSet of all ordered tuples from input sets.
Base CaseAdding the current list to results when depth meets input size.
Recursive ProcessBuild combinations through depth-first exploration and backtracking.

Applications

  • Configuration Generation: Used heavily in generating all possible configurations from sets of parameters.
  • Combinatorial Testing: Testing combinations of inputs or scenarios to ensure coverage.
  • Data Representation: Often involved in representing cross-joined datasets or matrices.

By efficiently using Java's collections and recursion, we've constructed a flexible solution to compute Cartesian products, enabling the handling of varied and complex inputs in practical applications. This approach not only enriches the learning experience but also arms developers with a toolset for tackling complex scenarios in computational tasks.


Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms