【问题标题】:How to multiply values in a list using java 8 streams如何使用java 8流将列表中的值相乘
【发布时间】:2016-08-18 10:51:01
【问题描述】:

流中是否有 sum() 等效方法可以执行流中给定值的乘法?

我有一个这样的整数列表:

List<Integer> listOfIntegers = new ArrayList<>();
listOfIntegers.addAll(Arrays.asList(1,4,2,7,5));

我能够得到所有整数的总和,但找不到可以将值相乘并给出输出的 API。

listOfIntegers.stream().mapToInt(a -> a).sum();

如果我尝试使用 forEach 来执行此操作,则我无法存储结果,因为其中只允许使用最终变量。

有没有其他选择?

【问题讨论】:

标签: java java-8 java-stream


【解决方案1】:

这是十进制产品的示例:

// Some list
List<Double> values;
...
double product = values.stream()
    .reduce(1.0, (acc, value) -> acc * value)
    .doubleValue();

【讨论】:

    【解决方案2】:

    对@Misha 的回答做出了贡献,因为我找到了一个示例,我们希望使用 BigInteger 而不是原始数据类型进行乘法运算。

    我正在解决这个 kata:Numbers with this digit inside,其中我们得到 x:一个 int 和 d:一个数字。我们需要找到从 1 到 x 中包含 d 的数字,并将其计数、和和乘法作为长数组返回。

    首先我尝试了以下代码:

    import java.util.*;
    
    public class Kata
    {
      public static long[] NumbersWithDigitInside(long x, long d)
      {
        if(d > x) return new long[3];
        List<Integer> list = new ArrayList<Integer>();
    
        for(int i = 1; i <= x; i++){
          String current = String.valueOf(i);
          if(current.contains(String.valueOf(d))){
            list.add(i);  
          }
        }
        return new long[]{list.size(),
                    list.stream().mapToInt(Integer::intValue).sum(),
                    list.stream().reduce(1, (a,b) -> a*b)};
      }
    }
    

    当我们执行以下测试时:

    import org.junit.Test;
    import static org.junit.Assert.assertArrayEquals;
    import org.junit.runners.JUnit4;
    
    public class SolutionTest {
        @Test
        public void BasicTests() {            
            assertArrayEquals(new long[] { 0, 0, 0 }, Kata.NumbersWithDigitInside(5, 6));        
            assertArrayEquals(new long[] { 1, 6, 6 }, Kata.NumbersWithDigitInside(7, 6));        
            assertArrayEquals(new long[] { 3, 22, 110 }, Kata.NumbersWithDigitInside(11, 1));        
            assertArrayEquals(new long[] { 2, 30, 200 }, Kata.NumbersWithDigitInside(20, 0));        
            assertArrayEquals(new long[] { 9, 286, 5955146588160L }, Kata.NumbersWithDigitInside(44, 4));
        }
    }
    

    它输出:

    arrays first differed at element [2]; expected:<5955146588160> but was:<-1973051392>
    

    因为在尝试最后一个测试用例时失败:

    assertArrayEquals(new long[] { 9, 286, 5955146588160L }, Kata.NumbersWithDigitInside(44, 4));
    

    所以要检查它是否是由于我替换的溢出:

    list.stream().reduce(1, (a,b) -> a*b)};
    

    与:

    list.stream().mapToInt(num->num).reduce(1, Math::multiplyExact)};
    

    那么,它会输出:

    java.lang.ArithmeticException: integer overflow
    

    最后我使用 BigInteger 如下:

    list.stream().map(BigInteger::valueOf).reduce(BigInteger.ONE, BigInteger::multiply).longValue()}
    

    作为完整的代码:

    import java.util.*;
    import java.math.BigInteger; 
    
    public class Kata
    {
      public static long[] NumbersWithDigitInside(long x, long d)
      {
        List<Integer> list = new ArrayList<Integer>();
    
        for(int i = 1; i <= x; i++){
          String current = String.valueOf(i);
          if(current.contains(String.valueOf(d))){
            list.add(i);  
          }
        }
    
        if(list.size() == 0) return new long[3];
    
        return new long[]{list.size(),
                    list.stream().mapToInt(Integer::intValue).sum(),
                    list.stream().map(BigInteger::valueOf).reduce(BigInteger.ONE, BigInteger::multiply).longValue()};
      }
    }
    

    ➡️欲了解更多信息:

    BigInteger class longValue()

    【讨论】:

      【解决方案3】:

      在乘以未知数量的 ints 时要记住的一件事是溢出的可能性。与(a,b) -&gt; a*b 相比,使用Math::multiplyExact 更安全,它会在溢出时抛出异常:

      listOfIntegers.stream().mapToInt(x->x).reduce(1, Math::multiplyExact);
      

      或者,您可以通过减少BigInteger 来适应较大的结果:

      listOfIntegers.stream()
          .map(BigInteger::valueOf)
          .reduce(BigInteger.ONE, BigInteger::multiply);
      

      如果列表为空,带有标识的归约将返回 1BigInteger.ONE,这可能不是您想要的。如果您希望处理空列表的情况,请删除reduce 的第一个参数,然后处理生成的Optional

      【讨论】:

        【解决方案4】:

        尝试减少流,它应该会有所帮助。

        喜欢:

        listOfIntegers.stream().reduce(1, (a, b) -> a * b)
        

        link 提供了有关如何使用 reduce 的更多信息。

        【讨论】:

        • 当然不用先装箱:IntStream.of(1,4,2,7,5).reduce(1, (a, b) -&gt; a * b)
        • 如果您可以得到Optional,那么您可以将第一个参数放到reduce
        猜你喜欢
        • 1970-01-01
        • 2018-05-30
        • 1970-01-01
        • 2020-11-29
        • 1970-01-01
        • 1970-01-01
        • 2020-11-27
        • 2021-11-06
        相关资源
        最近更新 更多