java流对所有值进行操作

时间:2017-10-21 15:48:20

标签: java java-8 java-stream

编辑 - 第二类没有基于索引的访问权限,而是实现可迭代

假设这样的类结构:

public class Values
{
    public int getValue(int i)
    {
        return values_[i];
    }

    private int[] values_;
}

和第二类这样的

public class ValuesCollection implements Iterable
{
    private Values[] valuesCollection_;
}

有没有办法使用java8流API来操作每个维度的统计数据,例如:sum,mean,min,max,range,variance,std等。例如[[2,4,8],[1, 5,7],[3,9,6]],为了获得最小值,它将返回[1,4,6]

我能想出的最接近的是:

public int[] getMin(ValuesCollection valuesCollection)
{

    IntStream.range(0, valuesCollection.size()).boxed().collect(Collectors.toList())
            .forEach(i -> {

                List<Integer> vals = valuesCollection.stream()
                        .map(values -> values.getValue(i))
                        .collect(Collectors.toList());

                // operate statistics on vals
                // no way to return the statistics
            });

}

2 个答案:

答案 0 :(得分:2)

你可以做到。我使用的是数组,而不是你的包装类。此外,我可能应该包含一些验证,即数组是矩形的,并使用orElseThrow而不是getAsInt,但你明白了。

int[][] vals = {{2, 4, 8}, {1, 5, 7}, {3, 9, 6}};

int[] min = IntStream
               .range(0, vals[0].length)
               .map(j -> IntStream.range(0, vals.length).map(i -> vals[i][j]).min().getAsInt())
               .toArray();

System.out.println(Arrays.toString(min));       // Prints [1, 4, 6] as expected

(因为我使用过数组,所以我可以用这行代替

.map(j -> Arrays.stream(vals).mapToInt(arr -> arr[j]).min().getAsInt())

但我写的就是像我一样对你的情况进行密切建模,你的对象不是数组,但确实有基于索引的访问。)

为标准差做这件事显然更难,但你可以把我的答案与this one结合起来。

修改

如果您的外部类没有基于索引的访问权限,而是实现Iterable,则可以将Iterable转换为Stream

Iterable<int[]> vals = Arrays.asList(new int[][] {{2, 4, 8}, {1, 5, 7}, {3, 9, 6}});

int[] min = IntStream
               .range(0, vals.iterator().next().length)
               .map(j -> StreamSupport.stream(vals.spliterator(), false).mapToInt(a -> a[j]).min().getAsInt())
               .toArray();

System.out.println(Arrays.toString(min));       // Prints [1, 4, 6] as expected

答案 1 :(得分:1)

你可以通过简单地将Integer [] []展平为Integer []然后以等于数组长度的周期对其进行操作来实现。 以下算法仅执行min,max,sum !!

   public class Test {
    public static void main(String... strings) {
            Integer[][] vals = {{2, 4, 8}, {1, 5, 7}, {3, 9, 6}};

            BinaryOperator<Integer> minFunction = (x, y) -> x < y? x: y;
            BinaryOperator<Integer> maxFunction = (x, y) -> x > y? x: y;
            BinaryOperator<Integer> sumFunction = (x, y) -> x+y;
    Integer[] performStatistic = performStatistic(vals, minFunction); // 1 4 6
    Integer[] performStatistic2 = performStatistic(vals, maxFunction); // 3 9 8
    Integer[] performStatistic3 = performStatistic(vals, sumFunction); // 6 18 21
            }

public static Integer[] performStatistic(Integer[][] vals, BinaryOperator<Integer> f){

            List<Integer> res = new ArrayList<>(vals.length);
            int[] i = {0};
    Arrays.asList(vals).stream().flatMap((Integer[] x)-> Arrays.asList(x).stream())
            .forEach(x -> {
                if(i[0]<vals.length){
                    res.add(i[0], x);
                }else{
                    int cyclicPos = i[0]%vals.length;
                    res.set(cyclicPos, f.apply(res.get(cyclicPos), x));
                }
                i[0]++;
            });
            return res.toArray(new Integer[res.size()]);
        }

    }

要执行其他操作,您可以按照相同的步骤操作,并使用BiFunction<Integer,Double,Double>执行范围,差异...... 也许以下可以帮助你!!

double avg = 100; // the avg you can get it from the previous algorithm
BiFunction<Integer,Double,Double> varianceFunction = (Integer x, Double y) -> {
            return  Math.pow(new Double(x) - avg, 2)+y;

        };// after getting the result just divided it by the (size of the array -1)