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

组合两个不同变量之和的Java流

谭景明
2023-03-14

我有一个问题。

public class TestVO {

    private String name;
    private String id;
    private int weight;
    private int height;

    public TestVO() {}
    
    public TestVO(String name, String id, int weight, int height) {
        this.name = name;
        this.id = id;
        this.height = height;
        this.weight = weight;
    }
    
    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Name: " + getName() + " ID: " + getId() + " Height: " + getHeight() + " Weight: " + getWeight();
    }
    
}
List<TestVO> tmpList = new ArrayList<>();
        
        tmpList.add(new TestVO("David", "id1", 10, 10));
        tmpList.add(new TestVO("", "id2", 11, 11));
        tmpList.add(new TestVO("Michael", "id3", 12, 12));
        tmpList.add(new TestVO("Jack", "id4", 13, 13));
        tmpList.add(new TestVO("Subodh", "id5", 14, 14));
        tmpList.add(new TestVO("", "id6", 15, 15));
        tmpList.add(new TestVO("Mrinal", "id7", 16, 16));
        tmpList.add(new TestVO("", "id8", 17, 17));
        tmpList.add(new TestVO("Eddie", "id9", 18, 18));
        tmpList.add(new TestVO("Peter", "id10", 19, 19));

我想做的是迭代tmpList,找到身高和体重的总和,并在名称为空时添加“No Name”。

// below into stream 
int totalWeight = 0;
int totalHeight = 0;
for (TestVO testVO : tmpList) {
    if( !"".equals(testVO.getName())){
        totalWeight += totalWeight;
        totalHeight += totalHeight;
    }else {
        testVO.setName("No-Name");
    }
}
Map<Boolean, List<TestVO>>tmpMap =  tmpList.stream()
            .collect(Collectors.partitioningBy(test -> !"".equals(test.getName())));
        
        
        int totalWeigt = tmpMap.get(true).stream()
                                            .mapToInt(test -> test.getWeight())
                                            .sum();
        
        int totalHeight = tmpMap.get(true).stream()
                                            .mapToInt(test -> test.getHeight())
                                            .sum();
            
        tmpMap.get(false).stream()
                            .forEach(test -> {
                                test.setName("No-Name");
                            });
        
        // method 1
        List<TestVO> tmpRet1 = Stream.of(tmpMap.get(true),  tmpMap.get(false)).flatMap(Collection::stream).collect(Collectors.toList());
        //method 2
        List<TestVO> tmpRet2 = Stream.concat(tmpMap.get(true).stream(), tmpMap.get(false).stream()).collect(Collectors.toList());  

我已经工作到目前为止,这似乎是不对的。我是说我必须重复每个案例。

有没有办法把它们结合在一起?或者有什么更好的建议?

共有3个答案

翟鹏
2023-03-14

如果确实希望在流中而不是在循环中执行所有这些操作:

// sums[0] = total weight, sums[1] = total height
int[] sums = tmpList.stream()
    .reduce(new int[]{0, 0},
            (acc, t) -> {
                if (t.getName().equals("")) {
                    t.setName("No-Name");
                    return acc;
                } else {                    
                    return new int[]{ acc[0] + t.getWeight(), acc[1] + t.getHeight()};
                }
            },
            (a, b) -> new int[]{ a[0] + b[0], a[1] + b[1] });

尽管流操作中的副作用通常不被鼓励。

夏才
2023-03-14

首先,循环版本似乎更适合此任务,该任务通过两个字段(按高度重量求和)进行聚合,并在遍历输入集合时修改空名称字段的状态,因为它确保整个输入只经过一次。

因此,"有状态"流操作作为foreach应该用于整个任务,但这与通常的for-each循环没有显著区别。一般来说,不建议使用这样的副作用操作:

_通常不鼓励行为参数对流操作产生副作用,因为它们通常会导致无意中违反无状态性要求,以及其他线程安全危险_

因此,如果任务被分成两个独立的子任务,使用流API分别解决每个任务将更合适。

  1. 使用聚合字段的容器聚合多个字段(容器可以实现为单独的对象/记录或字段的数组/集合)

使用Java16recordStream::reduce(BinaryOperator)的示例

record SumHeightWeight(int weight, int height) {
    SumHeightWeight sum(SumHeightWeight that) {
        return new SumHeightWeight(
            this.weight() + that.weight(),
            this.height() + that.height()
        );
    }
}

Predicate<TestVO> nonEmptyName = t -> !"".equals(t.getName());

SumHeightWeight sum = tmpList.stream()
    .filter(nonEmptyName)
    .map(t -> new SumHeightWeight(t.getWeight(), t.getHeight()))
    .reduce(SumHeightWeight::sum) // Optional<SumHeightWeight>
    .orElseGet(()-> new SumHeightWeight(0, 0));
System.out.println(sum); // -> SumHeightWeight[weight=102, height=102]
tmpList.stream()
    .filter(Predicate.not(nonEmptyName))
    .forEach(t -> t.setName("No-Name"));

水瀚漠
2023-03-14

它可以在流中的一次运行中完成:

  • 替换空名称

我改变了前两个的体重和身高,所以更明显的是结果是正确的。

import java.util.List;
import java.util.ArrayList;

public class Testing {
  public static void main(String[] args) {
    List<TestVO> tmpList = new ArrayList<>();
    tmpList.add(new TestVO("David", "id1", 100, 200));
    tmpList.add(new TestVO("", "id2", 2048, 1024));
    tmpList.add(new TestVO("Michael", "id3", 12, 12));
    tmpList.add(new TestVO("Jack", "id4", 13, 13));
    tmpList.add(new TestVO("Subodh", "id5", 14, 14));
    tmpList.add(new TestVO("", "id6", 15, 15));
    tmpList.add(new TestVO("Mrinal", "id7", 16, 16));
    tmpList.add(new TestVO("", "id8", 17, 17));
    tmpList.add(new TestVO("Eddie", "id9", 18, 18));
    tmpList.add(new TestVO("Peter", "id10", 19, 19));

    String NoName = "No-Name";

    int[] weigthHeight =
            tmpList.stream()
                    // modify the testVO
                   .map(testVO -> { if (testVO.getName().isEmpty()) {
                                     testVO.setName(NoName);
                                    }
                                    return testVO;
                    })
                    // it changed them:
                   .peek(testVO-> System.out.println(testVO))
                    // remove the ones we don't want anymore
                   .filter(testVO-> !NoName.equals(testVO.getName()))
                    // make an array of the Weight and Height
                   .map(testVO-> new int[]{testVO.getWeight(), testVO.getHeight()})
                    // reduce to one array with the sum of Weight and Height
                   .reduce(new int[]{0,0}, (a,b) -> add(a,b));

      System.out.println("Weight: " + weigthHeight[0]);
      System.out.println("Height: " + weigthHeight[1]);
  }

  static int[] add(int[] a, int[]b) {
    a[0] = a[0] + b[0];
    a[1] = a[1] + b[1];
    return a;
  }
}

它给了我这个机会:

Name: David ID: id1 Height: 200 Weight: 100
Name: No-Name ID: id2 Height: 1024 Weight: 2048
Name: Michael ID: id3 Height: 12 Weight: 12
Name: Jack ID: id4 Height: 13 Weight: 13
Name: Subodh ID: id5 Height: 14 Weight: 14
Name: No-Name ID: id6 Height: 15 Weight: 15
Name: Mrinal ID: id7 Height: 16 Weight: 16
Name: No-Name ID: id8 Height: 17 Weight: 17
Name: Eddie ID: id9 Height: 18 Weight: 18
Name: Peter ID: id10 Height: 19 Weight: 19
Weight: 192
Height: 292

我不确定这比使用一个方法获取重量和高度,另一个方法替换空名称更具可读性和透明性。

在溪流中跑步的感觉有点“黑”。它依赖于改变物体,我认为这是一种副作用。请参阅java包上的JavaDoc。util。关于“副作用”的信息流。首先是:

通常不鼓励行为参数对流操作产生副作用,因为它们通常会导致无意中违反无状态性要求,以及其他线程安全危险。

 类似资料:
  • 但是,要添加到我的txt文件中的事务列表的类型是Transaction,而不是String。 作为一个例子,这里有一些用户存款情况下的代码。 理想情况下,我希望代码读取用户以前的事务,将他们的新事务添加到txt文件的末尾,然后在用户完成时将所有这些事务保存到同一个txt文件中。有没有一种方法可以读取用户以前的事务类型为Transaction而不是String,或者以某种方式将这两个列表组合起来,给

  • 输出如下:http://imgur.com/a/nu3n6

  • 下面我有两个箱子。 案例1和案例2之间的区别在于案例2具有在中,但案例1在中具有。 问题是关于案例2的输出:为什么包含两个不同的值,一个是,另一个是字符串“B”?

  • 我有一个问题要用java来解决。 我的代码有三个变量:a、b、c,分别是双精度的。所有变量之和必须等于1。 我需要测试这些变量中所有可能的组合,值从0.10变化 示例: 组合1: 组合2: 然后继续。 是否有任何框架或库来自动化这种测试?

  • 但是,这并不适用于String类。请参见下面的代码: 这是因为字符串类和自声明类之间的差异吗?谢谢你的帮助!

  • 使用MongoDB 3.4。10和猫鼬4.13。6我能够计算用户模型上两个阵列的大小: 我的用户所在的位置(per) {“_id”:ObjectId(“5a2b21e63023c6117085c240”),“右投票”:[2],“左投票”:[1,6]} {“_id”:ObjectId(“5a2c0d68efde3416bc8b7020”),“右投票”:[2],“左投票”:[1]} 在这里,我得到了预