Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/373.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 按对象列表分组字段和计数出现次数_Java_Java Stream - Fatal编程技术网

Java 按对象列表分组字段和计数出现次数

Java 按对象列表分组字段和计数出现次数,java,java-stream,Java,Java Stream,我有一个列表,它包含像+或*这样的操作的所有操作数。也就是说,它不是二叉树结构,而是每个节点可能包含多个子节点的树。术语节点可以是变量、运算符、函数或数字。一个数字和一个变量节点包含一个空的子项列表(将子项视为操作的参数) 在simpleoperator方法的某个地方,我想用相同的值折叠变量。对于上面的表达式,树如下所示: _______ OPERATOR _______ / "+" \

我有一个
列表
,它包含像
+
*
这样的操作的所有操作数。也就是说,它不是二叉树结构,而是每个节点可能包含多个子节点的树。术语节点可以是变量、运算符、函数或数字。一个数字和一个变量节点包含一个空的子项列表(将子项视为操作的参数)

  • simpleoperator
    方法的某个地方,我想用相同的值折叠变量。对于上面的表达式,树如下所示:

                _______  OPERATOR  _______
               /           "+"            \
              /         /       \          \
        VARIABLE    VARIABLE   VARIABLE    VARIABLE
          "x"          "x"       "x"          "x"
    
     children.stream()
             .collect(Collector.toMap(
                   Function.identity(),
                   Collectors.summingInt(x -> 1),
                   (left, right) -> {
                        return left + right;// or left + 1
                   }
                   () -> new TreeMap<>(Comparator.comparing(TermNode::toCompareBy))
             ))
    
  • 目标是通过计算
    树节点
    中的
    子节点
    字段,将此树转换为更简单的树:此表达式由一个
    运算符
    TermNode和运算符+以及子节点列表组成,其中包含一个
    变量
    TermNode和值
    x
    四次(不是同一个TermNode的四次,只有四个TermNode具有完全相同的值、子项和类型。下面是我遇到的问题:

    private TermNode rearrangeTerm(Operator operator, List<TermNode> children) {
        Map<TermNode, Integer> occurrences = children.stream()
                .collect(Collectors.groupingBy(term -> term, Collectors.summingInt(term -> 1)));
    
        List<Pair<TermNode, Integer>> simplification = occurrences.entrySet().stream()
                .map(entry -> new Pair<TermNode, Integer>(entry.getKey(), entry.getValue())).collect(Collectors.toList());
    
        List<TermNode> rearranged = simplification.stream().map(pair -> rearrangeTerm(operator, pair)).collect(Collectors.toList());
    
        return new TermNode(operator.getOperator(), rearranged, TermTypeEnum.OPERATOR);
    }
    
    专用术语节点重新排列术语(运算符,列出子项){
    映射出现次数=children.stream()
    .collect(Collectors.groupby(term->term,Collectors.summingit(term->1));
    列表简化=引用。entrySet().stream()
    .map(entry->new Pair(entry.getKey(),entry.getValue()).collect(Collectors.toList());
    重新排列的列表=simplify.stream().map(对->重新排列项(运算符,对)).collect(收集器.toList());
    返回新的TermNode(operator.getOperator(),重新排列,TermTypeEnum.operator);
    }
    
    调用此方法时,将参数
    重新排列术语(运算符,子项)
    传递给方法,其中运算符是我们的
    +
    运算符,
    子项是我们的
    TermNode
    元素列表,其中包含变量
    x
    四次

    此时,
    term->term
    收集器。groupingBy
    不按字段值(值、子项和类型)对TermNode元素进行分组,而是作为TermNode引用本身。因此问题是,如何按字段对
    TermNode
    元素进行分组(如果两个
    TermNode
    元素的所有字段都匹配,则它们相等(子列表中元素的顺序可能不同,但重要的是每个
    TermNode
    的子列表中元素的出现情况匹配。当然
    TermNode
    类型也必须匹配。这里的问题只是如何更改
    重新排列term
    方法,以便映射对于表达式
    x+x+x+x+x
    ,只包含一个带有(“x”,4)的条目


  • 这将是太长的评论在这里,所以张贴作为一个答案

    因此,一般的想法是,您需要能够判断两个
    TermNode
    s对象是否相同;为此,您可以向对象添加一个方法,该方法将展平对象,并以某种方式从其每个字段递归计算一个
    String
    ,并按字母数字排序。因为您的对象仅由两个字段组成ds:
    value
    TermTypeEnum
    这并不难实现,类似的内容可能是(显然没有编译):

    私有列表展平;
    私有列表展平(TermNode节点){
    if(node.getChildren()>0){
    //这里有一些递归
    }否则{
    //这里可能有支票
    展平.add(node.value+node.type)
    }
    }
    //这将为您提供一个从所有值中排序的字符串
    用于比较的公共字符串(){
    返回flatned.sorted()。。。
    }
    
    所以你的代码是:

    Map<TermNode, Integer> occurrences = children.stream()
            .collect(Collectors.groupingBy(
                term -> term, 
                Collectors.summingInt(term -> 1)));
    
    Map引用数=children.stream()
    .collect(收集器.groupingBy(
    术语->术语,
    收集器。总和(术语->1));
    
    可能会变成这样:

                _______  OPERATOR  _______
               /           "+"            \
              /         /       \          \
        VARIABLE    VARIABLE   VARIABLE    VARIABLE
          "x"          "x"       "x"          "x"
    
     children.stream()
             .collect(Collector.toMap(
                   Function.identity(),
                   Collectors.summingInt(x -> 1),
                   (left, right) -> {
                        return left + right;// or left + 1
                   }
                   () -> new TreeMap<>(Comparator.comparing(TermNode::toCompareBy))
             ))
    
    children.stream()
    .collect(Collector.toMap(
    Function.identity(),
    收集器。总和(x->1),
    (左,右)->{
    返回left+right;//或left+1
    }
    ()->新树映射(Comparator.comparing(TermNode::toCompareBy))
    ))
    
    谢谢你的回答,我最终不得不重写我的
    TermNode
    类的
    equals(objectobj)
    hashCode()

    我跟踪了多个stackoverflow站点并使用了以下方法:

    @Override
    public boolean equals(Object other) {
        if(this == other) {
            return true;
        }
    
        if((other == null) || (other.getClass() != this.getClass())) {
            return false;
        }
    
        TermNode node = (TermNode)other;
    
        return this.value.equals(node.getValue()) 
                && PlotterUtil.isEqual(this.children, node.getChildren()) 
                && this.type == node.getType();
    }
    
    由于
    TermNode
    类包含一个
    List
    字段,因此需要检查参数列表是否也相等,但忽略参数的顺序,因为这些参数要么是单个值(如数字或单个变量),要么是包含在另一个
    TermNode
    中(如
    运算符)e> 函数
    永远不能忽略参数的顺序。为了检查两个列表是否相等,我使用了下面的代码

    publicstaticbooleaniesequal(列表一,列表二){
    if(一==null&&two==null){
    返回true;
    }
    if((一!=null&&two==null)| |(一==null&&two!=null)){
    返回false;
    }
    如果(1.size()!=2.size()){
    返回false;
    }
    一个=getSortedList(一个);
    两个=getSortedList(两个);
    返回1。等于(2);
    }
    
    这也解决了这个问题

    Map<TermNode, Integer> occurrences = 
        children.stream().collect(Collectors
            .groupingBy(term -> term, Collectors.summingInt(term -> 1))
        );
    
    Map引用=
    children.stream().collect(收集器
    .groupingBy(术语->术语,收集器.summingit(术语->1))
    );
    

    因为
    Map
    通过
    equals(Object obj)
    和对象的
    hashCode()
    方法检查
    term->term
    中的相等键。

    您能提供一个代数表达式,以及您希望它生成的成对列表吗?与
    相对应的代数表达式是什么
    
    public static boolean isEqual(List<TermNode> one, List<TermNode> two) {
        if(one == null && two == null) {
            return true;
        }
    
        if((one != null && two == null) || (one == null && two != null)) {
            return false;
        }
    
        if(one.size() != two.size()) {
            return false;
        }
    
        one = getSortedList(one);
        two = getSortedList(two);
    
        return one.equals(two);
    }
    
    Map<TermNode, Integer> occurrences = 
        children.stream().collect(Collectors
            .groupingBy(term -> term, Collectors.summingInt(term -> 1))
        );