如何创建类似于三个不同类型列表的笛卡尔积的数据结构?
How to create a data structure similar to the cartesian product of three lists of different types?
我想创建一个类似于三个列表的笛卡尔积的数据结构。
我还参考了 的现有答案,建议使用 flatMap。我也尝试过这种方式。但我的条件是 filterValue
列表在 types
列表中。所以 flatMap 在这里不起作用。因为 filterValues
可以是 0 or more
。因此,根据笛卡尔积(我们可能称之为组合)会发生变化。
每个列表的 measures, types & filterValues
大小可能不同。
如果 measure
列表为空。然后组合将只有 types & filterValues
(并且 measure
将设置为 null
。我在 if-else
块 [=35= 的评论中添加了这些不同的场景]
我有以下类型的列表:
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
然后我将上面的相同值设置为以下 classes:
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
}
classType
&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,
type.getType(),
new TypeCombi(type.getType(),
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, int = 1, double = 2.000000
str = null, int = 1, double = 3.000000
str = null, int = 2, double = 1.000000
str = null, int = 2, double = 2.000000
str = null, int = 2, double = 3.000000
str = null, int = 3, double = 1.000000
str = null, int = 3, 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, A, NULL, 03:00:00]
[1, B, null, 03:00:00]
[1, B, NULL, 03:00:00]
[2, A, null, 03:00:00]
[2, A, NULL, 03:00:00]
[2, B, null, 03:00:00]
[2, B, NULL, 03:00:00]
另请参阅:Find cartesian product of 2 lists
您可以创建一个通用方法,它接受不同类型的列表 List<? extends R>
和 returns 它们的超类型列表 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, 3, 6.6]
[1, 4, 5.5]
[1, 4, 6.6]
[2, 3, 5.5]
[2, 3, 6.6]
[2, 4, 5.5]
[2, 4, 6.6]
另请参阅:How to get Cartesian product from multiple lists?
我想创建一个类似于三个列表的笛卡尔积的数据结构。
我还参考了 filterValue
列表在 types
列表中。所以 flatMap 在这里不起作用。因为 filterValues
可以是 0 or more
。因此,根据笛卡尔积(我们可能称之为组合)会发生变化。
每个列表的 measures, types & filterValues
大小可能不同。
如果 measure
列表为空。然后组合将只有 types & filterValues
(并且 measure
将设置为 null
。我在 if-else
块 [=35= 的评论中添加了这些不同的场景]
我有以下类型的列表:
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
然后我将上面的相同值设置为以下 classes:
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
}
classType
&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,
type.getType(),
new TypeCombi(type.getType(),
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, int = 1, double = 2.000000
str = null, int = 1, double = 3.000000
str = null, int = 2, double = 1.000000
str = null, int = 2, double = 2.000000
str = null, int = 2, double = 3.000000
str = null, int = 3, double = 1.000000
str = null, int = 3, 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, A, NULL, 03:00:00]
[1, B, null, 03:00:00]
[1, B, NULL, 03:00:00]
[2, A, null, 03:00:00]
[2, A, NULL, 03:00:00]
[2, B, null, 03:00:00]
[2, B, NULL, 03:00:00]
另请参阅:Find cartesian product of 2 lists
您可以创建一个通用方法,它接受不同类型的列表 List<? extends R>
和 returns 它们的超类型列表 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, 3, 6.6]
[1, 4, 5.5]
[1, 4, 6.6]
[2, 3, 5.5]
[2, 3, 6.6]
[2, 4, 5.5]
[2, 4, 6.6]
另请参阅:How to get Cartesian product from multiple lists?