2016-01-20 9 views
1

Я пытаюсь использовать сокращение, чтобы суммировать значение HashMap.java уменьшить на массив в классе

public class Link 
{ 
    private double[] flows; 
    public Link(double[] f) { 
     setFlows(f); 
    } 
    public double[] getFlows() { 
     return flows; 
    } 
    public void setFlows(double[] flows) { 
     this.flows = flows; 
    } 

    public static void main(String argv[]) 
    { 
     // TEST for reduce on HashMap 
     HashMap<Integer, Link> id1 = new HashMap<Integer, Link>(); 
     id1.put(1, new Link(new double[]{10,1,30})); 
     id1.put(2, new Link(new double[]{20,2,3})); 
     id1.put(3, new Link(new double[]{30,2,3})); 
     id1.put(4, new Link(new double[]{40,2,30})); 

     double[] my_sum = new double[3]; 
     for (int i=0; i < 3; ++i) 
     { 
       my_sum[i] = id1.entrySet().stream().mapToDouble(e->e.getValue().getFlows()[i]).sum(); 
     } 
     assert(my_sum[0] == 100); 
     assert(my_sum[1] == 7); 
     assert(my_sum[2] == 66); 
    } 
} 

В цикле for я хочу суммировать значение каждого элемента массива в классе Link. Тем не менее, у меня есть проблема с:

локальной переменной, определенной в области видимости, должны быть окончательными и эффективно окончательное

В принципе я не хочу, чтобы определить окончательную переменную в качестве члена класса, как решить Это?

Или есть ли смысл суммировать стоимость? (без петли?)

+5

Это, вероятно, переменная 'i' здесь. Попробуйте определить окончательную копию внутри цикла, например. 'final int k = i', а затем использовать' getFlows() [k] 'в лямбда. – Thomas

+0

Также используется оператор приращения postfix: i ++ – eg04lt3r

+1

Префикс работает так же точно, как постфикс в циклах 'for'. – Keppil

ответ

3

Вы идете по нему не так: вы не должны иметь внешний цикл for, но обрабатывать все внутри конвейера Stream.

Вы можете настроить его работу с помощью storing the variable i into a final local variable.

В следующем коде сохраняются только значения карты (поскольку мы не заинтересованы в ключах). Затем каждое значение отображается на их потоки. Наконец, полученный Stream<double[]> уменьшается, сначала создавая массив из 3 элементов (инициализированный до 0), а затем объединяя два двойных массива в полученный результат путем суммирования значения в том же самом индексе.

Мы должны полагаться на использование Stream над индексами для этого, потому что нет встроенного средства для прошивки двух потоков вместе.

double[] my_sum = 
    id1.values().stream() 
       .map(Link::getFlows) 
       .reduce(
        new double[3], 
        (v1, v2) -> IntStream.range(0, v2.length).mapToDouble(i -> v1[i] + v2[i]).toArray() 
       ); 

System.out.println(Arrays.toString(my_sum)); // prints [100.0, 7.0, 66.0] 
+2

как побочная заметка, вам нужно как-то убедиться, что все массивы имеют одинаковую длину. вы можете вставить некоторую проверку конструктора Link для длины. – Aarjav

+0

@Tunaki, огромное спасибо! – stevenhz

0

Если добавить add метод (изготовление Link изменчивый, к сожалению), вы можете использовать в Link на сумму тоже.

// Makes it mutable - will try immutable later 
    public void add(Link other) { 
     for (int i = 0; i < flows.length; i++) { 
      flows[i] += other.flows[i]; 
     } 
    } 

    public static void main(String argv[]) { 
     // TEST for reduce on HashMap 
     HashMap<Integer, Link> id1 = new HashMap<>(); 
     id1.put(1, new Link(new double[]{10, 1, 30})); 
     id1.put(2, new Link(new double[]{20, 2, 3})); 
     id1.put(3, new Link(new double[]{30, 2, 3})); 
     id1.put(4, new Link(new double[]{40, 2, 30})); 

     Link sum = new Link(new double[3]); 
     id1.entrySet().stream().forEach(l -> sum.add(l.getValue())); 
    } 
+0

Спасибо. Синтаксис здесь проще. – stevenhz

2

Альтернативой, которая выглядит лучше меня использовать Arrays.setAll:

double[] my_sum = new double[3]; 
Arrays.setAll(my_sum, 
    i -> id1.entrySet().stream().mapToDouble(e->e.getValue().getFlows()[i]).sum()); 

Здесь i эффективно окончательным.

 Смежные вопросы

  • Нет связанных вопросов^_^