我有一段代码Cognitive Complexity为21
for (String item1 : itemList1){
for (String item2 : itemList2){
for (String item3 : itemList3){
for (String item4 : itemList4){
for (String item5 : itemList5){
for (String item6 : itemList6){
methodToRun(item1, item2, item3, item4, item5, item6);
}
}
}
}
}
}
我们的linter指定最大认知复杂度为15,所以我应该按照我们一直遵循的标准来减少它。
有人可以为这段代码提出替代解决方案吗?或者尽管复杂性太高,它仍然可以接受吗?
我知道这可能是个人意见,但我正在寻找以前遇到类似情况的人的真实解决方案或答案。
编辑:我无法从我正在开发的开发机器上访问很多库和软件包。我可以访问一些(列表太多),所以在建议使用之前请注意这一点。答案 0 :(得分:3)
您可以选择递归解决方案。可以说它的可读性较差,但嵌套级别要小得多,这降低了复杂性度量:
static void recursiveRun(List<List<String>> list, int pos, String[] item) {
if (pos == 6) {
methodToRun(item[0], item[1], item[2], item[3], item[4], item[5]);
} else {
for (String s : list.get(pos)) {
item[pos] = s;
recursiveRun(list, pos+1, item);
}
}
}
初始通话如下:
recursiveRun(
Arrays.asList(itemList1, itemList2, itemList3, itemList4, itemList5, itemList6)
, 0
, new String[6]
);
答案 1 :(得分:2)
将数据打包到List<List<String>>
后,您就可以使用 n-ary Cartesian产品来保留Google Guava中实现的元素顺序(词典编纂)。
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
List<List<String>> input = Arrays.asList(
ImmutableList.of("Mary", "Alice"),
ImmutableList.of("Smith", "Darcy", "Brown"),
ImmutableList.of("Ford", "Saab")
);
List<List<String>> result = Lists.cartesianProduct(input); //Cognitive Complexity of 0
for (List<String> shuffle: result) {
System.out.println(String.join(",", shuffle));
}
...生产:
Mary,Smith,Ford
Mary,Smith,Saab
Mary,Darcy,Ford
Mary,Darcy,Saab
Mary,Brown,Ford
Mary,Brown,Saab
Alice,Smith,Ford
Alice,Smith,Saab
Alice,Darcy,Ford
Alice,Darcy,Saab
Alice,Brown,Ford
Alice,Brown,Saab
这是一个快速解决方案,其中包含3个列表的硬编码值,可能会在不产生太多复杂性惩罚的情况下进行推广。它基本上会做一些简洁(又名难以遵循)的索引计算。
String[] list0 = new String[] {"0", "1"};
String[] list1 = new String[] {"4", "5"};
String[] list2 = new String[] {"8", "9"};
int[] indexes = new int[3];
long totalPermutations = list0.length * list1.length * list2.length;
for(int i = 0; i < totalPermutations; i++) {
indexes[0] = i % list0.length;
indexes[1] = (i / list0.length) % list1.length;
indexes[2] = (i / (list0.length * list1.length)) % list2.length;
System.out.println(list0[indexes[0]] + "," + list1[indexes[1]] + "," + list2[indexes[2]]);
}
纯Java解决方案是一个完美的例子,为了保持度量标准的快乐,我们实际上增加了复杂性和可维护性。
整个指数计算都非常可怕,并且很少有人去做对。无论如何,一般解决方案很可能会花费一些惩罚,因为需要进行迭代。我在网上找到的其他解决方案(包括递归和功能)并不比一堆嵌套循环更清晰。
在这里发明笛卡儿的产品例程将使IMO更加复杂(即使评分较低的复杂性)也无法理解。
软件必须建立在抽象的基础上,并且使用开放的,精心设计的第三方依赖性可以使整个问题得到很好的解决。
答案 2 :(得分:2)
这是一个基于迭代器的解决方案。
class CartesianProductIterator<T> implements Iterator<List<T>>, Iterable<List<T>> {
private List<List<T>> data;
private int size;
private int[] sizes;
private int[] cursors;
private boolean done;
public CartesianProductIterator(List<List<T>> data) {
this.data = data;
this.size = data.size();
this.sizes = new int[this.size];
this.cursors = new int[this.size];
setSizes(data);
}
@Override
public boolean hasNext() {return !done;}
@Override
public List<T> next() {
if (! hasNext()) throw new NoSuchElementException();
ArrayList<T> tuple = new ArrayList<>();
for (int i = 0; i < size; i++) {tuple.add(data.get(i).get(cursors[i]));}
updateCursors();
return tuple;
}
private void updateCursors() {
for (int i = size - 1; i >= 0; i--) {
if (cursors[i] < sizes[i] - 1) {
cursors[i]++;
break;
} else {
cursors[i] = 0;
if (i == 0) done = true;
}
}
}
private void setSizes(List<List<T>> data) {
for (int i = 0; i < size; i++) {sizes[i] = data.get(i).size();}
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove is not supported here");
}
@Override
public Iterator<List<T>> iterator() {return this;}
}
可用于按需创建交叉产品
List<List<String>> data = new ArrayList<>();
data.add(Arrays.asList("a", "b", "c"));
data.add(Arrays.asList("1", "2"));
data.add(Arrays.asList("A", "B", "C"));
Iterator<List<String>> dataIterator = new CartesianProductIterator<String>(data);
while (dataIterator.hasNext()) {
System.out.println(dataIterator.next());
}
现在使用双Iterable / Iterator接口可以替代地用作
for(List<String> combination: new CartesianProductIterator<>(data)) {
System.out.println(combination);
}
答案 3 :(得分:0)
我想用一些可行的代码跟进我的评论。然后我意识到递归部分非常像@dasblinkenlight(我向你保证这不是有意的),所以我犹豫发布这个(只是参考他的)。然而,这更通用一点。我正在推动@dasblinkenlight。
public class CartesianProduct {
public static void main(String[] args) {
List<String> l1 = new ArrayList<String>(Arrays.asList("a", "b", "c"));
List<String> l2 = new ArrayList<String>(Arrays.asList("d", "e", "f"));
List<String> l3 = new ArrayList<String>(Arrays.asList("g", "h"));
processCartesianProduct(new MyCartesianProductTask(), l1, l2, l3);
}
private static void processCartesianProduct(CartesianProductTask task, List<String>... lists) {
processCP(task, new String[lists.length], 0, lists);
}
private static void processCP(CartesianProductTask task, String[] element, int pos, List<String>... lists) {
if (pos == lists.length)
task.doTask(element);
else {
for (String s : lists[pos]) {
element[pos] = s;
processCP(task, element, pos+1, lists);
}
}
}
interface CartesianProductTask {
public void doTask(String[] element);
}
static class MyCartesianProductTask implements CartesianProductTask {
@Override
public void doTask(String[] element) {
System.out.println("Performing task on: "+Arrays.asList(element));
// Business logic goes here
}
}
}
产地:
Performing task on: [a, d, g]
Performing task on: [a, d, h]
Performing task on: [a, e, g]
Performing task on: [a, e, h]
Performing task on: [a, f, g]
Performing task on: [a, f, h]
Performing task on: [b, d, g]
Performing task on: [b, d, h]
Performing task on: [b, e, g]
Performing task on: [b, e, h]
Performing task on: [b, f, g]
Performing task on: [b, f, h]
Performing task on: [c, d, g]
Performing task on: [c, d, h]
Performing task on: [c, e, g]
Performing task on: [c, e, h]
Performing task on: [c, f, g]
Performing task on: [c, f, h]
答案 4 :(得分:0)
这是一个基于计算笛卡尔积中的索引的解决方案:
i
中的索引可以通过除以子空间的大小和将结果与向量的大小进行MOD来计算。这是一个实现:
static void iterateCartesian(List<List<String>> lists) {
int[] size = new int[lists.size()+1];
size[lists.size()] = 1;
for (int i = lists.size()-1 ; i >= 0 ; i--) {
size[i] = size[i+1]*lists.get(i).size();
}
for (int i = 0 ; i != size[0] ; i++) {
methodToRun(
lists.get(0).get((i/size[1]) % lists.get(0).size())
, lists.get(1).get((i/size[2]) % lists.get(1).size())
, lists.get(2).get((i/size[3]) % lists.get(2).size())
, lists.get(3).get((i/size[4]) % lists.get(3).size())
, lists.get(4).get((i/size[5]) % lists.get(4).size())
, lists.get(5).get((i/size[6]) % lists.get(5).size())
);
}
}
这个解决方案相当平稳,#34;但它需要相当数量的定量能力来理解。
答案 5 :(得分:-1)
我不主张采用这种方法,但我认为它(a)会抑制警告,(b)可能会让你思考如何突破代码以帮助它更有意义。我发现它比原版更清晰或更具可读性,但根据所有术语在您的上下文中的含义,它可能会提示有用的新方向。
Select Rules -> Add Rule -> required tag