问题描述
我想创建一个类似于三个List的笛卡尔积的DataStructure。
我还参考了Jurgen的现有答案,建议使用flatMap。我也尝试过这种方式。但是我已经确定filterValue
列表位于types
列表内。因此,flatMap在这里不起作用。由于filterValues
可以是0 or more
。因此,根据笛卡尔积(我们可以称其为组合),它会发生变化。
每个列表的measures,types & filterValues
大小可以不同。
如果measure
列表为空。然后,组合将只有types & filterValues
(并且measure
将设置为null
。我在if-else
块的注释中添加了这些不同的方案
我有以下几种类型的列表:
-
List<String> measures
-
List<Type> types
-
List<FilterValue> filterValues
例如,输入结构为:
{
"measures": [
"m1","m2","m3"
],"types": [
{
"type": "type-1",//some more fields
"filterValues": [
//no filter values present
]
},{
"type": "type-2",//some more fields
"filterValues": [
{
"filterValue": "t2f1"
//some more fields
},{
"filterValue": "t2f2"
//some more fields
}
]
}
]
}
然后在上述情况下,我期望的输出数据结构是
m1 type-1 null
m1 type-2 t2f1
m1 type-2 t2f2
m2 type-1 null
m2 type-2 t2f1
m2 type-2 t2f2
m3 type-1 null
m3 type-2 t2f1
m3 type-2 t2f2
然后将相同的上述值设置为以下类别:
class SearchArea{
String measure;
String type;
TypeCombi typeFileter;
//constructor for measure & type
//constructor for all three
//getters & setters
}
class TypeCombi{
String type;
String name; //it is mapped with filterValue
//constructor for above two fields
//getters & setters
}
类Type
和FilterValue
如下
class Type{
String type;
List<FilterValue> filterValues;
//some more fields
//getters and setters
}
class FilterValue{
String filterValue;
//some more fields
//getters and setters
}
我可以使用以下getSearchAreas
函数来达到预期的输出。但是在这种情况下,我使用了多个(两个)for
循环。可以使用stream/flatmap
而不是两个for loops
清除此代码块吗?
还有没有更好的方法来处理多个if / else块?(我已经在每种if / else块上方添加了注释)
private List<SearchArea> getSearchAreas(List<String> measures,List<Type> types){
List<SearchArea> searchAreas = new ArrayList<>();
//measures & types both are empty
if((measures==null || measures.isEmpty()) && (types==null || types.isEmpty()))
return Collections.emptyList();
//one or more measure and zero types
else if(measures!=null && !measures.isEmpty() && (types==null || types.isEmpty())){
searchAreas = measures
.stream()
.map(measure-> new SearchArea(measure,null))
.collect(Collectors.toList());
return searchAreas;
}
//zero measures and one or more types
else if((measures == null || measures.isEmpty())){
for (type type : types) {
if(type.getFilterValues()==null || type.getFilterValues().isEmpty()){
searchAreas.add(new SearchArea(null,type.getType()));
}
else{
searchAreas.addAll(type.getFilterValues()
.stream()
.map(filterValue-> new SearchArea(null,type.getType(),new TypeCombi(type.getType(),filterValue.getFilterValue())))
.collect(Collectors.toList()));
}
}
return searchAreas;
}
//one or more measures and one or more types
else{
for (String measure : measures) {
for (Type type : types) {
if(type.getFilterValues()==null || type.getFilterValues().isEmpty()){
searchAreas.add(new SearchArea(measure,type.getType()));
}
else{
searchAreas.addAll(type.getFilterValues()
.stream()
.map(filterValue-> new SearchArea(measure,filterValue.getFilterValue())))
.collect(Collectors.toList()));
}
}
}
return searchAreas;
}
}
如果有人能以清洁的方式帮助我进行上述重组,那就太好了。
解决方法
我想这就是你想要的。请注意,有时不使用流会更干净。
public static void main(String[] args) throws Exception {
List<String> strings = Collections.emptyList();
List<Integer> ints = Arrays.asList(1,2,3);
if (strings == null || strings.isEmpty()) {
strings = Collections.singletonList(null);
}
if (ints == null || ints.isEmpty()) {
ints = Collections.singletonList(null);
}
for (String str : strings) {
for (Integer integer : ints) {
// In your code doubles comes from a property of integer.
List<Double> doubles = integer == null ? Collections.emptyList() : Arrays.asList(1.0d,2.0d,3.0d);
if (doubles == null || doubles.isEmpty()) {
doubles = Collections.singletonList(null);
}
for (Double doubler : doubles) {
// Create your object here.
System.out.format(Locale.US," str = %s,int = %d,double = %f %n",str,integer,doubler);
}
}
}
}
输出如下:
str = null,int = 1,double = 1.000000
str = null,double = 2.000000
str = null,double = 3.000000
str = null,int = 2,double = 1.000000
str = null,double = 2.000000
str = null,int = 3,double = 3.000000
,
您可以获取三个或更多不同类型列表的笛卡尔积,并将其存储到对象 List<List<Object>>
的列表列表中。
public static List<List<Object>> cartesianProduct(List<?>... lists) {
// incorrect incoming data
if (lists == null) return Collections.emptyList();
return Arrays.stream(lists)
// non-null and non-empty lists
.filter(list -> list != null && list.size() > 0)
// represent each list element as SingletonList<Object>
.map(list -> list.stream().map(Collections::<Object>singletonList)
// Stream<List<List<Object>>>
.collect(Collectors.toList()))
// summation of pairs of inner lists
.reduce((list1,list2) -> list1.stream()
// combinations of inner lists
.flatMap(inner1 -> list2.stream()
// merge two inner lists into one
.map(inner2 -> Stream.of(inner1,inner2)
.flatMap(List::stream)
.collect(Collectors.toList())))
// list of combinations
.collect(Collectors.toList()))
// returns List<List<Object>>,otherwise an empty list
.orElse(Collections.emptyList());
}
public static void main(String[] args) {
List<Integer> list1 = Arrays.asList(1,2);
List<String> list2 = Arrays.asList("A","B");
List<Object> list3 = Arrays.asList(null,"NULL");
List<Time> list4 = Collections.singletonList(new Time(0));
List<List<Object>> lists = cartesianProduct(list1,list2,list3,list4);
// output
lists.forEach(System.out::println);
}
输出:
[1,A,null,03:00:00]
[1,NULL,B,03:00:00]
[2,03:00:00]
另见:Find cartesian product of 2 lists
,您可以创建一个通用方法,该方法接受不同类型 List<? extends R>
的列表并返回其超类型 List<R>
的列表。
/**
* @param lists a list of lists for multiplication
* @param <R> the supertype of the elements
* @return the Cartesian product
*/
public static <R> List<List<R>> cartesianProduct(List<List<? extends R>> lists) {
// check if incoming data is not null
if (lists == null) return Collections.emptyList();
// Cartesian product,intermediate result
List<List<R>> cp = Collections.singletonList(Collections.emptyList());
// iterate through incoming lists
for (List<? extends R> list : lists) {
// non-null and non-empty lists
if (list == null || list.size() == 0) continue;
// intermediate result for next iteration
List<List<R>> next = new ArrayList<>();
// rows of current intermediate result
for (List<R> row : cp) {
// elements of current list
for (R el : list) {
// new row for next intermediate result
List<R> 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<Integer> l1 = Arrays.asList(1,2);
List<Long> l2 = Arrays.asList(3L,4L);
List<Double> l3 = Arrays.asList(5.5D,6.6D);
List<List<Number>> cp = cartesianProduct(Arrays.asList(l1,l2,l3));
// output
for (List<Number> row : cp) System.out.println(row);
}
输出:
[1,3,5.5]
[1,6.6]
[1,4,6.6]
[2,5.5]
[2,6.6]