替代多个嵌套的 for 和 if 块
Alternative to multiple nested for and if blocks
我正在尝试实现一个我使用多个 for 循环和 if 条件编写的复杂块,而不是那么复杂。初始代码为
for(Coll_Monthly_Main monthlyAccount:monthlyList){
for(Coll_Daily_Main dailyAccount:dailyList){
if(monthlyAccount.getAccountId().trim().equals(dailyAccount.getAccountId().trim())){
for(Catg_Monthly monthlyCategory: monthlyAccount.getCatg()){
for(Catg_Daily dailyCategory: dailyAccount.getCatg()){
if(monthlyCategory.getPriCatId().trim().equals(dailyCategory.getPriCatId().trim())){
monthlyCategory.setMthTtl(dailyCategory.getMthTtl());
monthlyCategory.setMtd(dailyCategory.getMtd());
monthlyCategory.setYtd(dailyCategory.getYtd());
for(SecCatDtl_Mthly monthlySecCategory:monthlyCategory.getSecCatDtl()){
for(SecCatDtl_Daily dailySecCategory:dailyCategory.getSecCatDtl()){
if(monthlySecCategory.getCatId().trim().equals(dailySecCategory.getCatId().trim())){
monthlySecCategory.setMthTtl(dailySecCategory.getMthTtl());
monthlySecCategory.setMtd(dailySecCategory.getMtd());
monthlySecCategory.setYtd(dailySecCategory.getYtd());
}
}
}
}
}
}
}
}
}
return monthlyList;
我已经按照这个 并成功地实现了第一级,如下所示:-
monthlyList.forEach(coll_mthly->{
dailyList.stream().filter(coll_daily->coll_mthly.getAccountId().trim().equals(coll_daily.getAccountId().trim()))
.forEach(catg_mth->coll_mthly.getCatg())->{
};
});
对于下一级嵌套,我需要遍历嵌套列表,但我不确定如何进行。我不断收到如下语法错误:-
令牌语法错误,应该是 TypeElidedFormalParameter
如果有任何正确方向的指示,我将不胜感激。
更新:-
Thomas 的回答是这样的
Map<String, Coll_Daily_Main> dailies = dailyList.stream().collect(Collectors.toMap(cdm -> cdm.getAccountId(), cdm-> cdm) );
for(Coll_Monthly_Main monthlyAccount : monthlyList) {
Coll_Daily_Main dailiesForAccount = dailies.get( monthlyAccount.getAccountId().trim());
Map<String, Catg_Daily> dailyCatgories=dailiesForAccount.getCatg().stream().collect(Collectors.toMap(cv->cv.getPriCatId(), cv->cv));
for(Catg_Monthly monthlyCategory:monthlyAccount.getCatg()){
Catg_Daily dailyCategory = dailyCatgories.get(monthlyCategory.getPriCatId().trim());
if(dailyCategory!=null){
monthlyCategory.setMthTtl(dailyCategory.getMthTtl());
monthlyCategory.setMtd(dailyCategory.getMtd());
monthlyCategory.setYtd(dailyCategory.getYtd());
Map<String,SecCatDtl_Daily> dailySecCategories=dailyCategory.getSecCatDtl().stream().collect(Collectors.toMap(fg->fg.getCatId(), fg->fg));
for(SecCatDtl_Mthly monthlySecCategory:monthlyCategory.getSecCatDtl()){
SecCatDtl_Daily dailySecCategory =dailySecCategories.get(monthlySecCategory.getCatId().trim());
if(dailySecCategory!=null){
monthlySecCategory.setMthTtl(dailySecCategory.getMthTtl());
monthlySecCategory.setMtd(dailySecCategory.getMtd());
monthlySecCategory.setYtd(dailySecCategory.getYtd());
}
}
}
}
}
正如其他人已经多次指出的那样,最好重新考虑您的方法并使其不仅更具可读性而且更快。我想到的一件事:你有 3 个级别,由 2 个循环和一个 if 组成,用于检查元素是否匹配(通过 id)。这些级别将具有 O(n*m) 复杂性。
但是,您可以尝试以 id 作为键构建一个映射或多映射(Guava 有一些)并将其降低到 O(n + m):
- O(n) 用于构建地图(理想情况下在较大的集合上,即每天)
- O(m) 用于迭代第二组(理想情况下是较小的一组,即每月一次)
- 查找应为 O(1),因此可以忽略
我不确定所有这些嵌套级别是什么意思,所以我只能举一个例子说明你可以为一个级别做些什么(我会选择第一个):
//I'm using Google Guava's classes here
SetMultimap<String, Coll_Daily_Main> dailies = ...;//use one that fits your needs
//Iterate over n daily entries and put them into the map which should be O(n)
dailyList.forEach( cdm -> dailies.put( cdm.getAccountId().trim(), cdm ) );
//Iterate over the (smaller) set of monthly entries and do a lookup for the dailies which should be O(m)
for(Coll_Monthly_Main monthlyAccount : monthlyList) {
Set<Coll_Daily_Main> dailiesForAccount = dailies.get( monthlyAccount.getAccountId().trim() );
//level done, either go down to the next or try to further straighten it out or optimize
}
更新:
我忘了说你不必将 Guava 与 Java 8 一起使用。虽然使用 Map<String, Set<Coll_Daily_Main>>
的定义看起来有点尴尬,但不是 "hard"再:
Map<String, Set<String>> dailies = new HashMap<>();
dailyList.forEach( cdm -> dailies.computeIfAbsent( cdm.getAccountId().trim(), v -> new HashSet<>() ).add( cdm ) );
注意:您还可以使用收集器使其更短一些并在一行中。这是否更易于阅读和使用还有待商榷。
Map<String, Set<Daily>> dailies =
dailyList.stream().collect( Collectors.groupingBy( cdm -> cdm.getAccountId().trim(),
Collectors.toSet() ) );
- 首先,您需要在私有方法中提取所有 if 语句。
- 然后你就可以开始用 lambdas 重构你的 for 语句了。
您甚至可以声明一个静态函数(在下面的示例中称为 loop
)来导出您的嵌套循环逻辑:
public class Test {
public List<Coll_Monthly_Main> runThatThing(List<Coll_Monthly_Main> monthlyList, List<Coll_Daily_Main> dailyList) {
loop(monthlyList, dailyList, Test::updateMonthlyCategories);
return monthlyList;
}
private static void updateMonthlyCategories(Coll_Monthly_Main monthlyAccount, Coll_Daily_Main dailyAccount) {
if(monthlyAccount.getAccountId().trim().equals(dailyAccount.getAccountId().trim())){
loop(monthlyAccount.getCatg(), dailyAccount.getCatg(), Test::updateMonthlyCategory);
}
}
private static void updateMonthlyCategory(Catg_Monthly monthlyCategory, Catg_Daily dailyCategory) {
if(monthlyCategory.getPriCatId().trim().equals(dailyCategory.getPriCatId().trim())){
monthlyCategory.setMthTtl(dailyCategory.getMthTtl());
monthlyCategory.setMtd(dailyCategory.getMtd());
monthlyCategory.setYtd(dailyCategory.getYtd());
loop(monthlyCategory.getSecCatDtl(), dailyCategory.getSecCatDtl(), Test::updateMonthlySecondCategory);
}
}
private static void updateMonthlySecondCategory(SecCatDtl_Mthly monthlySecCategory, SecCatDtl_Daily dailySecCategory) {
if(monthlySecCategory.getCatId().trim().equals(dailySecCategory.getCatId().trim())){
monthlySecCategory.setMthTtl(dailySecCategory.getMthTtl());
monthlySecCategory.setMtd(dailySecCategory.getMtd());
monthlySecCategory.setYtd(dailySecCategory.getYtd());
}
}
// nested loops through list1 and list2 which apply the function `f` to all pairs.
//Using a BiConsumer because the f methods we use always return void
private static <T, U> void loop(List<T> list1, List<U> list2, BiConsumer<T, U> f) {
list1.forEach(
element1 -> list2.forEach(
element2 -> f.accept(element1, element2)
));
}
}
我正在尝试实现一个我使用多个 for 循环和 if 条件编写的复杂块,而不是那么复杂。初始代码为
for(Coll_Monthly_Main monthlyAccount:monthlyList){
for(Coll_Daily_Main dailyAccount:dailyList){
if(monthlyAccount.getAccountId().trim().equals(dailyAccount.getAccountId().trim())){
for(Catg_Monthly monthlyCategory: monthlyAccount.getCatg()){
for(Catg_Daily dailyCategory: dailyAccount.getCatg()){
if(monthlyCategory.getPriCatId().trim().equals(dailyCategory.getPriCatId().trim())){
monthlyCategory.setMthTtl(dailyCategory.getMthTtl());
monthlyCategory.setMtd(dailyCategory.getMtd());
monthlyCategory.setYtd(dailyCategory.getYtd());
for(SecCatDtl_Mthly monthlySecCategory:monthlyCategory.getSecCatDtl()){
for(SecCatDtl_Daily dailySecCategory:dailyCategory.getSecCatDtl()){
if(monthlySecCategory.getCatId().trim().equals(dailySecCategory.getCatId().trim())){
monthlySecCategory.setMthTtl(dailySecCategory.getMthTtl());
monthlySecCategory.setMtd(dailySecCategory.getMtd());
monthlySecCategory.setYtd(dailySecCategory.getYtd());
}
}
}
}
}
}
}
}
}
return monthlyList;
我已经按照这个
monthlyList.forEach(coll_mthly->{
dailyList.stream().filter(coll_daily->coll_mthly.getAccountId().trim().equals(coll_daily.getAccountId().trim()))
.forEach(catg_mth->coll_mthly.getCatg())->{
};
});
对于下一级嵌套,我需要遍历嵌套列表,但我不确定如何进行。我不断收到如下语法错误:- 令牌语法错误,应该是 TypeElidedFormalParameter
如果有任何正确方向的指示,我将不胜感激。
更新:- Thomas 的回答是这样的
Map<String, Coll_Daily_Main> dailies = dailyList.stream().collect(Collectors.toMap(cdm -> cdm.getAccountId(), cdm-> cdm) );
for(Coll_Monthly_Main monthlyAccount : monthlyList) {
Coll_Daily_Main dailiesForAccount = dailies.get( monthlyAccount.getAccountId().trim());
Map<String, Catg_Daily> dailyCatgories=dailiesForAccount.getCatg().stream().collect(Collectors.toMap(cv->cv.getPriCatId(), cv->cv));
for(Catg_Monthly monthlyCategory:monthlyAccount.getCatg()){
Catg_Daily dailyCategory = dailyCatgories.get(monthlyCategory.getPriCatId().trim());
if(dailyCategory!=null){
monthlyCategory.setMthTtl(dailyCategory.getMthTtl());
monthlyCategory.setMtd(dailyCategory.getMtd());
monthlyCategory.setYtd(dailyCategory.getYtd());
Map<String,SecCatDtl_Daily> dailySecCategories=dailyCategory.getSecCatDtl().stream().collect(Collectors.toMap(fg->fg.getCatId(), fg->fg));
for(SecCatDtl_Mthly monthlySecCategory:monthlyCategory.getSecCatDtl()){
SecCatDtl_Daily dailySecCategory =dailySecCategories.get(monthlySecCategory.getCatId().trim());
if(dailySecCategory!=null){
monthlySecCategory.setMthTtl(dailySecCategory.getMthTtl());
monthlySecCategory.setMtd(dailySecCategory.getMtd());
monthlySecCategory.setYtd(dailySecCategory.getYtd());
}
}
}
}
}
正如其他人已经多次指出的那样,最好重新考虑您的方法并使其不仅更具可读性而且更快。我想到的一件事:你有 3 个级别,由 2 个循环和一个 if 组成,用于检查元素是否匹配(通过 id)。这些级别将具有 O(n*m) 复杂性。
但是,您可以尝试以 id 作为键构建一个映射或多映射(Guava 有一些)并将其降低到 O(n + m):
- O(n) 用于构建地图(理想情况下在较大的集合上,即每天)
- O(m) 用于迭代第二组(理想情况下是较小的一组,即每月一次)
- 查找应为 O(1),因此可以忽略
我不确定所有这些嵌套级别是什么意思,所以我只能举一个例子说明你可以为一个级别做些什么(我会选择第一个):
//I'm using Google Guava's classes here
SetMultimap<String, Coll_Daily_Main> dailies = ...;//use one that fits your needs
//Iterate over n daily entries and put them into the map which should be O(n)
dailyList.forEach( cdm -> dailies.put( cdm.getAccountId().trim(), cdm ) );
//Iterate over the (smaller) set of monthly entries and do a lookup for the dailies which should be O(m)
for(Coll_Monthly_Main monthlyAccount : monthlyList) {
Set<Coll_Daily_Main> dailiesForAccount = dailies.get( monthlyAccount.getAccountId().trim() );
//level done, either go down to the next or try to further straighten it out or optimize
}
更新:
我忘了说你不必将 Guava 与 Java 8 一起使用。虽然使用 Map<String, Set<Coll_Daily_Main>>
的定义看起来有点尴尬,但不是 "hard"再:
Map<String, Set<String>> dailies = new HashMap<>();
dailyList.forEach( cdm -> dailies.computeIfAbsent( cdm.getAccountId().trim(), v -> new HashSet<>() ).add( cdm ) );
注意:您还可以使用收集器使其更短一些并在一行中。这是否更易于阅读和使用还有待商榷。
Map<String, Set<Daily>> dailies =
dailyList.stream().collect( Collectors.groupingBy( cdm -> cdm.getAccountId().trim(),
Collectors.toSet() ) );
- 首先,您需要在私有方法中提取所有 if 语句。
- 然后你就可以开始用 lambdas 重构你的 for 语句了。
您甚至可以声明一个静态函数(在下面的示例中称为 loop
)来导出您的嵌套循环逻辑:
public class Test {
public List<Coll_Monthly_Main> runThatThing(List<Coll_Monthly_Main> monthlyList, List<Coll_Daily_Main> dailyList) {
loop(monthlyList, dailyList, Test::updateMonthlyCategories);
return monthlyList;
}
private static void updateMonthlyCategories(Coll_Monthly_Main monthlyAccount, Coll_Daily_Main dailyAccount) {
if(monthlyAccount.getAccountId().trim().equals(dailyAccount.getAccountId().trim())){
loop(monthlyAccount.getCatg(), dailyAccount.getCatg(), Test::updateMonthlyCategory);
}
}
private static void updateMonthlyCategory(Catg_Monthly monthlyCategory, Catg_Daily dailyCategory) {
if(monthlyCategory.getPriCatId().trim().equals(dailyCategory.getPriCatId().trim())){
monthlyCategory.setMthTtl(dailyCategory.getMthTtl());
monthlyCategory.setMtd(dailyCategory.getMtd());
monthlyCategory.setYtd(dailyCategory.getYtd());
loop(monthlyCategory.getSecCatDtl(), dailyCategory.getSecCatDtl(), Test::updateMonthlySecondCategory);
}
}
private static void updateMonthlySecondCategory(SecCatDtl_Mthly monthlySecCategory, SecCatDtl_Daily dailySecCategory) {
if(monthlySecCategory.getCatId().trim().equals(dailySecCategory.getCatId().trim())){
monthlySecCategory.setMthTtl(dailySecCategory.getMthTtl());
monthlySecCategory.setMtd(dailySecCategory.getMtd());
monthlySecCategory.setYtd(dailySecCategory.getYtd());
}
}
// nested loops through list1 and list2 which apply the function `f` to all pairs.
//Using a BiConsumer because the f methods we use always return void
private static <T, U> void loop(List<T> list1, List<U> list2, BiConsumer<T, U> f) {
list1.forEach(
element1 -> list2.forEach(
element2 -> f.accept(element1, element2)
));
}
}