当前位置: 首页 > 知识库问答 >
问题:

为什么这个未使用的流会对结果产生影响?

游鸣
2023-03-14

为什么以下未有效使用的行(在方法中:getAllDefinedVars)会对最终结果产生影响:
List collect=AllVars.Stream().Filter(v->false).collect(Collectors.ToList());

如果我删除整个方法和调用此方法的一行代码(generateOneSetOfBools中的第一行),我最终会得到另一个结果。
如果...

  1. 提到的行对列表allVars或任何其他变量有影响
  2. 将使用流的结果

就我所见,这些都没有发生。因此,删除整个方法应该不会对结果产生影响。

为了说服自己,您可以第一次使用包含流的方法运行main,第二次不使用该方法运行main,然后比较输出。

public class PairwiseMain {
    
    private static PairwisePermutator pp = new PairwisePermutator();

    public static void main(String[] args) {
        for(int i = 0; i < 20; i++) {
            pp.permutate(i);
            System.out.println("----------------");
        }
    }

}



import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class PairwisePermutator {
    
    private int n;
    
    public Stream<boolean[]> permutate(int n) {
        this.n = n;
        List<Var> vars = generateRequiredVars(n);
        List<TupleSet> table = generateTable(vars);
        generateCombinations(table, vars);
        return null;
    }
    
    private void generateCombinations(List<TupleSet> table, List<Var> vars) {
        TupleSet start = findStartTupleSet(table);
        if(start == null) {
            return; 
        }else {
            Tuple t = start.tuples.get(0);
            start.setVars(t);
            generateOneSetOfBools(table, vars, new HashSet<>(Arrays.asList(start)));
        }
        System.out.println(Arrays.toString(vars.toArray()));
        resetAllVars(vars);
        generateCombinations(table, vars);
    }

    private void resetAllVars(List<Var> vars) {
        vars.stream().forEach(v -> v.value = null);
    }

    private void generateOneSetOfBools(List<TupleSet> table, List<Var> allVars, Set<TupleSet> start) {
        List<Var> alreadyDefinedVars = getAllDefinedVars(allVars); //REMOVAL OF THIS LINE SHOULD HAVE NO IMPACT
        Map<TupleSet, Integer> relevant = findRelevantTuplesInOtherTupleSets(table, start);
        boolean changes = false;
        boolean existsMultipleOptions = false;
        TupleSet minimalMultipleOptions = null;
        int minimalMultipleOptionsNumber = Integer.MAX_VALUE;
        for(Map.Entry<TupleSet, Integer> entry : relevant.entrySet()) {
            if(entry.getValue() == -1) {
                removeTuple(entry.getKey());
                start.add(entry.getKey());
                changes = true;
            }else if(entry.getValue() == 1) {   
                changes = true;
                removeTuple(entry.getKey(), table, allVars);
                start.add(entry.getKey());
            }else if(entry.getValue() >= 2) {    
                existsMultipleOptions = true;
                if(entry.getValue() < minimalMultipleOptionsNumber) {
                    minimalMultipleOptionsNumber = entry.getValue();
                    minimalMultipleOptions = entry.getKey();
                }
            }
        }
        if(!changes && existsMultipleOptions) {
            removeRandomTuple(minimalMultipleOptions, start);
        }else if(!changes) { 
            setVars(table);
        }
        if(areAllVarsDefined(allVars)) {
            removeMatchingTuples(table);
            return;
        }
        generateOneSetOfBools(table, allVars, start);
    }

    private List<Var> getAllDefinedVars(List<Var> allVars) {
        List<Var> collect = allVars.stream().filter(v -> false).collect(Collectors.toList());
        return collect;
    }

    private void removeMatchingTuples(List<TupleSet> table) {
        for(TupleSet ts : table) {
            boolean v1 = ts.x.value;
            boolean v2 = ts.y.value;
            Tuple toRemove = null;
            for(Tuple t : ts.tuples) {
                if(t.a == v1 && t.b == v2) {
                    toRemove = t;
                }
            }
            if(toRemove != null) {
                ts.setVars(toRemove);
            }
        }
    }

    private boolean areAllVarsDefined(List<Var> allVars) {
        return allVars.stream().filter(v -> v.value != null).count() == n;
    }

    private void removeRandomTuple(TupleSet minimalMultipleOptions, Set<TupleSet> start) {
        Tuple toRemove = minimalMultipleOptions.tuples.get(0);
        minimalMultipleOptions.setVars(toRemove);
        start.add(minimalMultipleOptions);
    }

    private void setVars(List<TupleSet> table) {
        boolean foundOne = false;
        for(TupleSet ts : table) {
            if(ts.x.value == null && ts.y.value == null) {
                foundOne = setVars(ts);
            }
        }
        if(!foundOne) {
            for(TupleSet ts : table) {
                if(ts.x.value == null || ts.y.value == null) {
                    if(ts.tuples.isEmpty()){
                        ts.x.value = true;
                        ts.y.value = false;
                    }else {
                        ts.setVars(ts.tuples.get(0));
                    }
                }
            }
        }
        
    }

    private boolean setVars(TupleSet ts) {
        boolean foundOne;
        if(ts.tuples.isEmpty()){
            ts.x.value = true;
            ts.y.value = false;
            foundOne = true;
        }else {
            ts.setVars(ts.tuples.get(0));
            foundOne = true;
        }
        return foundOne;
    }

    private void removeTuple(TupleSet ts, List<TupleSet> table, List<Var> vars) {
        Tuple toRemove = null;
        if(ts.x.value != null) {
            for(Tuple t : ts.tuples) {
                if(t.a == ts.x.value) {
                    toRemove = t;
                }
            }
        }else if(ts.y.value != null) {
            for(Tuple t : ts.tuples) {
                if(t.b == ts.y.value) {
                    toRemove = t;
                }
            }
        }
        if(toRemove != null)
            ts.setVars(toRemove);
    }

    private void removeTuple(TupleSet ts) {
        boolean v1 = ts.x.value;
        boolean v2 = ts.y.value;
        Tuple toRemove = null;
        for(Tuple t : ts.tuples) {
            if(t.a == v1 && t.b == v2) {
                toRemove = t;
            }
        }
        if(toRemove != null) {
            ts.setVars(toRemove);
        }
    }

    private Map<TupleSet, Integer> findRelevantTuplesInOtherTupleSets(List<TupleSet> table, Set<TupleSet> alreadyVisited) {
        Map<TupleSet, Integer> freedomMap = new HashMap<>();
        for(TupleSet ts : table) {
            if(!alreadyVisited.contains(ts)) {
                int degreeOfFreedom = calculateDegreeOfFreedom(ts);
                freedomMap.put(ts, degreeOfFreedom);            }
        }
        return freedomMap;
    }
    
    private int calculateDegreeOfFreedom(TupleSet ts) {
        List<Var> alreadyDefinedVars = new ArrayList<>();
        if(ts.x.value != null) {
            alreadyDefinedVars.add(ts.x);
        }
        if(ts.y.value != null) {
            alreadyDefinedVars.add(ts.y);
        }
        int degreeOfFreedom = 0;
        if(areBothDefinied(alreadyDefinedVars)) {
            degreeOfFreedom = -1; 
        }else if(isExactlyOneDefinied(alreadyDefinedVars)) {
            Var defined = getDefinedVar(alreadyDefinedVars);
            if(defined == ts.x) {
                degreeOfFreedom = (int) ts.tuples.stream().filter(t -> t.a == ts.x.value).count();
            }else if(defined == ts.y) {
                degreeOfFreedom = (int) ts.tuples.stream().filter(t -> t.b == ts.y.value).count();
            }
        }else if(alreadyDefinedVars.isEmpty()) {
            degreeOfFreedom = ts.tuples.size(); 
        }
        return degreeOfFreedom;
    }

    private Var getDefinedVar(List<Var> alreadyDefinedVars) {
        return alreadyDefinedVars.get(0);
    }

    private boolean isExactlyOneDefinied(List<Var> alreadyDefinedVars) {
        return alreadyDefinedVars.size() == 1;
    }

    private boolean areBothDefinied(List<Var> alreadyDefinedVars) {
        return alreadyDefinedVars.size() == 2;
    }

    private TupleSet findStartTupleSet(List<TupleSet> table) {
        TupleSet startingTupleSet = null;
        for(TupleSet ts : table) {
            if(!ts.tuples.isEmpty()) {
                startingTupleSet = ts;
            }
        }
        return startingTupleSet;
    }

    private List<Var> generateRequiredVars(int n) {
        return IntStream.range(0, n).mapToObj(number -> new Var()).collect(Collectors.toList());
    }
    
    private List<TupleSet> generateTable(List<Var> vars) {
        List<TupleSet> tupleSets = new ArrayList<>();
        int kStart = 1;
        for(int i = 0; i < vars.size(); i++) {
            for(int k = kStart; k < vars.size(); k++) {
                tupleSets.add(getInitSet(vars.get(i), vars.get(k)));
            }
            kStart++;
        }
        return tupleSets;
    }
    
    private TupleSet getInitSet(Var x, Var y){
        return new TupleSet(x, y, (new ArrayList<>(Arrays.asList( new Tuple(true, true),
                                            new Tuple(true, false),
                                            new Tuple(false, true),
                                            new Tuple(false, false)))));
    }
    
    private static class TupleSet{
        Var x;
        Var y;
        ArrayList<Tuple> tuples;
        
        TupleSet(Var x, Var y, ArrayList<Tuple> tuples){
            this.x = x;
            this.y = y;
            this.tuples = tuples;
        }
        
        public void setVars(Tuple t) {
            x.value = t.a;
            y.value = t.b;
            tuples.remove(t);
        }

        @Override
        public String toString() {
            return "["+x+","+y+"]"+tuples;
        }
    }
    
    private static class Var{
        public Boolean value;
        
        @Override
        public String toString() {
            return value == null ? "null" : value.toString();
        }
    }
    
    private static class Tuple{
        public Boolean a;
        public Boolean b;
        
        public Tuple(Boolean a, Boolean b) {
            this.a = a;
            this.b = b;
        }
        
        @Override
        public String toString() {
            return "("+a+","+b+")";
        }
    }

}

[true, true, true, true, true]  
[false, false, false, true, false]  
[false, false, false, false, true]  
[true, true, true, false, false]  
[true, false, false, true, false]  
[false, false, true, true, false]  
[true, true, true, false, false] 

没有流:只删除generateOneSetOfBool()中的第一行

[true, true, true, true, true]  
[false, false, false, true, false]  
[false, false, false, false, true]  
[true, true, true, false, false]  
[false, true, true, true, false]  
[true, false, true, true, false]  
[true, true, false, false, false]  

两个输出不同,例如最后一行

共有1个答案

谯和煦
2023-03-14

您得到的结果差异与行列表collect=allvars.stream().filter(v->false).collect(collectors.tolist());无关。问题是你的算法是非确定性的。我已经取下您的代码,并为相同的输入多次运行它:

for(int i = 0; i < 20; i++) {
    pp.permutate(5);
    System.out.println("----------------");
}

不管你说的是不是有行--我得到了你提到的两个输出(只有这两个变体出现):

[true, true, true, true, true]
[false, false, false, true, false]
[false, false, false, false, true]
[true, true, true, false, false]
[true, false, false, true, false]
[false, false, true, true, false]
[true, true, true, false, false]
----------------
[true, true, true, true, true]
[false, false, false, true, false]
[false, false, false, false, true]
[true, true, true, false, false]
[false, true, true, true, false]
[true, false, true, true, false]
[true, true, false, false, false]

我没有逐行遍历您的代码,所以我不确定,但我猜您的一些集合不能保证元素的顺序。

然而,有趣的是,当我多次运行main时,不同版本的输出出现的顺序总是相同的(或者至少在我尝试的5次中)。更重要的是,当您提到的一行被移除时,顺序会发生变化--但在main调用之间保持不变。当我们再加上在不同的机器上它的行为是不同的这一事实时,我的结论是,它可能与程序在内存中的放置方式有关。

 类似资料:
  • 当我发现这个奇怪的东西时,我正在玩JSX。使用以下JSX: 会产生正确的结果: 但我想在引号周围添加双引号,因此我尝试: 令我惊讶的是,它给出了正确的输出: 我希望得到类似的输出,因为它是字符串文字: 既然在字符串文本中,它为什么不按字面意思告诉我?这是巴贝尔的错误吗? 注意:这是一个自我提问和回答

  • 我正在使用递归编写回文检查器。我很困惑为什么删除 函数末尾的语句影响返回值。 代码#1: 对于所有回文,这将返回true,对于所有非回文,返回false。 代码#2: 这只对一些回文返回 true,对于所有非回文,这返回 false。 回文,例如, amanaplanacanalpanama 返回false,此时应返回true。 通过测试,表明基本大小写是使用最后一个回文输入的,这意味着函数将其视

  • 为什么这段代码不生成这样的表; 你会注意到,我想要的格式把所有类似的Y变量在那里自己的块(表)和当我读代码在我的脑海中它应该这样做,但没有这样的运气对我来说,3天与这微不足道的11行代码和我已经尝试了十几个或更多的变化相同的代码和无论我做什么它总是搞砸了这个当前版本产生的结果组合在一起只有X值=5然后噗丢弃所有的其余数据 以上代码的结果:

  • 问题内容: 我怀疑Java代码中未使用的导入和未使用的对象是否会对性能产生影响? 假设一个对象已初始化并且从未使用过,会发生什么?未使用进口的成本是多少 问题答案: 这是一个非常普遍的问题。 像大多数性能问题一样,最好的方法是编写最清晰,最简单的代码,因为这样可以提高代码的可维护性,并有助于确保代码即使更改后也能正常运行。(聪明/难以理解/不必要地开始,详细的代码可以快速运行,但是由于只是凡人而改

  • 为什么运算符只应该是4个字节却生成12个字节?当我引用变量时,这只是引用数组第一个索引的内存地址。实际上,我打印了第一个索引的内存地址,并将其与进行了比较,它们产生了相同的内存地址结果,这证实了它们都引用了数组的第一个索引,但是“array”产生了12个字节,而产生了4个字节。

  • 问题内容: 从相对不规范的形式获取数据库并将其规范化时,人们可能期望资源利用率 发生 什么 变化 (如果有)? 例如,规范化通常意味着可以从更少的表中创建更多的表,这意味着数据库现在具有更多的表,但是其中许多表都非常小,可以使经常使用的表更好地适合内存。 表的数量越多,意味着(潜在地)需要更多的联接才能获取抽象出的数据,因此,人们可能会期望系统需要执行的联接数量越多,就会产生某种影响。 那么,标准