英文:
How to create a data structure similar to the cartesian product of three lists of different types?
问题
I want to create a DataStructure which will be similar to the cartesian product of three List.
I've also referred the existing answer by Jurgen which suggests to use flatMap. I tried in that way as well. But I've a condition that filterValue
list is inside types
list. So flatMap will not work here. As filterValues
can be 0 or more
. So depending on that cartesian product (we might call it as combination) will change.
Size of measures, types & filterValues
can be different for each list.
If measure
list is empty. Then the combination will be of only types & filterValues
(and measure
will be set to null
. I've added these different scenarios in my comments of if-else
block
I've following types of list:
List<String> measures
List<Type> types
List<FilterValue> filterValues
For example the Input structure is:
{
"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
}
]
}
]
}
Then in the above case the output data structure I'm expecting is
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
Then the same above values I'm setting into the following classes:
class SearchArea {
String measure;
String type;
TypeCombi typeFilter;
//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
}
The class Type
& FilterValue
is as below
class Type {
String type;
List<FilterValue> filterValues;
//some more fields
//getters and setters
}
class FilterValue {
String filterValue;
//some more fields
//getters and setters
}
I'm able to achieve the expected output using the following getSearchAreas
function. But in this case I'm using multiple(two) for
loops. Can this code block be cleaned up using stream/flatMap
instead of two for loops
?
Also is there any better way to handle multiple if/else block? (I've added a comment above each if/else block for its scenario)
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;
}
}
It will be great if someone can help me restructure the above in a cleaner fashion.
英文:
I want to create a DataStructure which will be similar to the cartesian product of three List.
I've also referred the existing answer by Jurgen which suggest to use flatMap. I tried in that way as well. But I've condition that filterValue
list is inside types
list. So flatMap will not work here. As filterValues
can be 0 or more
. So depending on that cartesian product (we might call it as combination) will change.
Size of measures, types & filterValues
can be different for each list.
If measure
list is empty. Then the combination will be of only types & filterValues
(and measure
will be set to null
. I've added these different scenarios in my comments of if-else
block
I've following types of list:
List<String> measures
List<Type> types
List<FilterValue> filterValues
For example the Input structure is:
{
"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
}
]
}
]
}
Then in above case the output data structure I'm expecting is
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
Then the same above values I'm setting into the following 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
}
The class Type
& FilterValue
is as below
class Type {
String type;
List<FilterValue> filterValues;
//some more fields
//getters and setters
}
class FilterValue {
String filterValue;
//some more fields
//getters and setters
}
I'm able to achieve the expected output using following getSearchAreas
function. But in this case I'm using multiple(two) for
loops. Can this code block cleaned up using stream/flatmap
instead of two for loops
?
Also is there any better way to handle multiple if/else block ?(I've added comment above each if/else block for it's scenario)
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;
}
}
It will be great if someone can help me in restructuring above in cleaner fashion.
答案1
得分: 1
这是你想要的内容。请注意,有时不使用流可能更清晰。
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);
}
}
}
}
Output follows:
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
英文:
I think this is what you want. Note that it is sometimes cleaner not to use streams.
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);
}
}
}
}
Output follows:
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
答案2
得分: 1
以下是您提供的内容的翻译:
您可以获得三个或更多不同类型的列表的笛卡尔积,并将其存储在一个对象的列表列表 List<List<Object>>
中。
public static List<List<Object>> cartesianProduct(List<?>... lists) {
// 不正确的输入数据
if (lists == null) return Collections.emptyList();
return Arrays.stream(lists)
// 非空且非空列表
.filter(list -> list != null && list.size() > 0)
// 将每个列表元素表示为 SingletonList<Object>
.map(list -> list.stream().map(Collections::<Object>singletonList)
// Stream<List<List<Object>>>
.collect(Collectors.toList()))
// 内部列表对的求和
.reduce((list1, list2) -> list1.stream()
// 内部列表的组合
.flatMap(inner1 -> list2.stream()
// 将两个内部列表合并为一个
.map(inner2 -> Stream.of(inner1, inner2)
.flatMap(List::stream)
.collect(Collectors.toList())))
// 组合列表
.collect(Collectors.toList()))
// 返回 List<List<Object>>,否则返回空列表
.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);
// 输出
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]
<sup>另请参见:查找两个列表的笛卡尔积</sup>
英文:
You can get the Cartesian product of three or more lists of different types and store it into a list of lists of objects 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);
}
Output:
[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]
<sup>See also: Find cartesian product of 2 lists</sup>
答案3
得分: 0
你可以创建一个通用方法,接受不同类型的列表 List<? extends R>
,并返回它们的超类型列表 List<R>
。
/**
* @param lists 用于乘法的列表的列表
* @param <R> 元素的超类型
* @return 笛卡尔积
*/
public static <R> List<List<R>> cartesianProduct(List<List<? extends R>> lists) {
// 检查传入的数据是否不为空
if (lists == null) return Collections.emptyList();
// 笛卡尔积,中间结果
List<List<R>> cp = Collections.singletonList(Collections.emptyList());
// 遍历传入的列表
for (List<? extends R> list : lists) {
// 非空且非空列表
if (list == null || list.size() == 0) continue;
// 下一次迭代的中间结果
List<List<R>> next = new ArrayList<>();
// 当前中间结果的行
for (List<R> row : cp) {
// 当前列表的元素
for (R el : list) {
// 下一个中间结果的新行
List<R> nRow = new ArrayList<>(row);
nRow.add(el);
next.add(nRow);
}
}
// 传递到下一次迭代
cp = next;
}
// 笛卡尔积,最终结果
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));
// 输出
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]
另请参阅:如何从多个列表中获取笛卡尔积?
英文:
You can create a generic method that accepts lists of different types List<? extends R>
and returns a lists of their supertype 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);
}
Output:
[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]
<sup>See also: How to get Cartesian product from multiple lists?</sup>
1: https://tio.run/##hVTBThsxEL3vV8xxE4WlQOHQhLQVXCqhCoVj1YPxOonBa1v2GEpLvj0dO5tks7vASoll@828meeZeWBP7MhYoR/Kx/VaVtY4hAc6LAJKVQzHWefsRnocZxlXzHu4uoV/GdB3PBymFYbwzTLHKlCE88DSCmZe7@fGQRUUSqskZyiNbplNZlPa4lKAD1Y4fLEiWscDoUQlNPqdhRMYnE53V8yh8JJpsM6UgWMNOk6rDfdEBx6JkSeKmMUk/c2mU@Bb69uNcb6//griDwpdeojAlMSgzjnlfQx8KfgjyDlIzU0l9QJKhgykB20QdFBqhyZQvtHh8jLdDKDO4cooJXjUwxeisvgSyfPBuEnUyXFElChcJUrJUJArT8ruLFopWrg8YPEUqRJodGJ6g/8wAElkkQiXzoTFcp9wymmHjG@cd8TbFMKXroS1c230UZQEmC7TJoXRct0UcashvL4mFGX0V@SDePxpANxolDqIcZunR7IUsaZQ6wx3VdmrZAIStXiG786xpNRk2nyrmsmZZx9rlwfnqG7ffaxD3UgtMiaxuG0rVfve9kLTfxShg01OZ4Svpe/zt30ByijS7tX4IOADfShmPSPrrjLksyXO9osGBSvLXKi3EBRHQkRoD2aVvb2jlGwcUmjee9zUGPF@73z1QdfNpWaqLUjdyNxu/KyynsnzZGQJFZM6v0NHjfPrNzC3OOiGpNkPEn4hHPXMCQWXtPQF86knT0Zw2hBiU5tGLwh82gGf3Yzg800bfm0oKkEGZx2D8@L8egQXxcU1GfWMkp@huqfA6nnSmZuHzhTFqk7pd9YaJCagDdgzMGr3jeq/e/EoqoIsCkuSodKNelplq/X6Pw "Java (OpenJDK 8) – Try It Online"
2: https://stackoverflow.com/a/68629936/16596785
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论