Java - How to build unique object tuples (n-dimension)?

风格不统一 提交于 2019-12-12 04:38:59

问题


I have the following challenge that I need to create unique object tuples out of object lists. The speical challenge is here how I can do it for dynamic list sizes (n-dimension)? It is easy in case you have a fixed dimension. I hope somebody knows a third party API or has some hints for me how I can reach this.

The exampel below shows it for a 3 lists, so it is easier to explain. I have the objects sorted by its class in a list e.g.

lista = {a1,a2}
listb = {b1,b2,b3}
listc = {c1,c2}

I like to have the following tuples, so that each object is paired once with each other:

tuple1  = {a1,b1,c1}
tuple2  = {a1,b1,c2}
tuple3  = {a1,b2,c1}
tuple4  = {a1,b2,c2}
tuple5  = {a1,b3,c1}
tuple6  = {a1,b3,c2}
tuple7  = {a2,b1,c1}
tuple8  = {a2,b1,c2}
tuple9  = {a2,b2,c1}
tuple10 = {a2,b2,c2}
tuple11 = {a2,b3,c1}
tuple12 = {a2,b3,c2}

How can I achieve that in case
- the number of lists is dynamically
- the size of lists is dynamically

any hints or ideas? Thank you in advance


回答1:


We can build up to the solution as follows. First notice that the case in which the sizes of the lists vary is never a problem in modern languages, because virtually all languages today support the variable-sized list. The trickier part is when the number of lists vary.

Here is the Python case for the fixed number of lists:

lista = ["a1","a2"]
listb = ["b1","b2","b3"]
listc = ["c1","c2"]
[(a,b,c) for a in lista for b in listb for c in listc]

For Java do the same thing. You will need three nested for-loops:

List<String> lista = Arrays.asList("a1","a2");
List<String> listb = Arrays.asList("b1","b2","b3");
List<String> listc = Arrays.asList("c1","c2");

List<List<String>> result = new ArrayList<List<String>>();
for (String a: lista) {
    for (String b: listb) {
        for (String c: listc) {
            result.add(Arrays.asList(a, b, c));
        }
    }
}
System.out.println(result);

This yields

[[a1, b1, c1], [a1, b1, c2], [a1, b2, c1], [a1, b2, c2], [a1, b3, c1], [a1, b3, c2], [a2, b1, c1], [a2, b1, c2], [a2, b2, c1], [a2, b2, c2], [a2, b3, c1], [a2, b3, c2]]

Now the trick is how do you do an indeterminate number of for loops? One way is to use recursion.

Start with the base case of 0 lists (or even 1) and then ask yourself: how does the result change when I add a new list? Then you can put together a nice little recursive formulation. Do you need help with this?

(Aside: In Python we have itertools for these kinds of things. I am not aware of any Java analog, but some googling might turn something up.)

Okay let's develop the recursive formulation for an unbounded number of lists. If you have only only one list, say

a = ["a1", "a2"]

then the result is [["a1"],["a2"]]. But now let's add another list:

a = ["b1", "b2"]

What is the answer now?

[[a1, b1], [a1, b2], [a2, b1], [a2, b2]]

How did we get that? The answer is we took each element of the new list and appended it to each element in the result. And every time we add a new list we will do the same. Suppose now we add ["c1","c2","c3"]. Do you see what we will get? If so, you should now be able to define the recursive step!

COMPLETE CODE

Okay I could not resist! Here you go.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * An application requested by a SO user.
 */
public class ProductExample {

    /**
     * Returns a list containing all possible products of a list of lists of strings.
     */
    public static List<List<String>> product(List<List<String>> lists) {
        List<List<String>> result = new ArrayList<List<String>>();

        if (lists.isEmpty()) {
            result.add(new ArrayList<String>());
            return result;
        }

        List<List<String>> partial = product(lists.subList(0, lists.size() - 1));
        for (List<String> list: partial) {
            for (String s: lists.get(lists.size() - 1)) {
                List<String> listCopy = new ArrayList<String>(list);
                listCopy.add(s);
                result.add(listCopy);
            }
        }
        return result;
    }


    public static void main(String[] args) {
        System.out.println(product(
                Arrays.asList(
                        Arrays.asList("a1", "a2"),
                        Arrays.asList("b1", "b2", "b3"),
                        Arrays.asList("c1", "c2"),
                        Arrays.asList("d1", "d2"))));
    }
}

Rant: This is sooooooo much easier in Python. Or Ruby. :)




回答2:


Something like this should work (treat as pseudocode):

List<List<int>> result = new List<List<int>>();
int[] indices = new int[number_of_lists];
for(int i = 0; i < indices.size(); i++)
  indices[i] = 0;

while(indices[0] < lists[0].size())
{
  List<int> temp = new List<int>();
  for(int i = 0; i < indices.size(); i++)
    temp.add(lists[i].get(indices[i]));
  result.add(temp);

  indices[indices.size() - 1] += 1;
  int i = indices.size();
  while(i >= 1 && indices[i] == lists[i].size())
  {
    indices[i] = 0;
    indices[i-1] += 1;
    i--;
  }
}



回答3:


Sets of Google Guava seems to do something similar to what you want, at least for the case of your example. You will however need to cast the resulting lists into tuple forms. Also these are Sets, not Lists, but your example at least had no duplicate entries, so maybe this helps you.



来源:https://stackoverflow.com/questions/7022500/java-how-to-build-unique-object-tuples-n-dimension

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!