2015-06-07 2 views
11

Я хочу сгенерировать список чисел с использованием лямбда-выражений, а не для цикла.Лямбда-выражения в Java 8

Итак, давайте скажем, я хочу, чтобы создать список всех треугольных чисел под 100. треугольных чисел числа, которые следуют по формуле: (п * п + п)/2

Что такое лучший способ сделать это ? В настоящее время у меня есть это:

Stream.iterate(1, n -> n + 1).limit(100) 
      .map(n -> (n * n + n)/2) 
      .filter(a -> a < 100) 
      .map(a -> a + "") 
      .collect(Collectors.joining(", ", "Numbers: ", ".")); 

Но это, кажется, излишне излишеством с количеством вычислений. Я повторяю n от 1 до 100 (потому что позволяет предположить, что я не знаю, что такое максимальное значение для n), тогда я сопоставляю функцию номера треугольника этого списка, а затем проверяю, какие числа меньше 100. Есть ли более эффективный способ в этом? Также: могу ли я генерировать числа треугольников, используя только функцию итерации потока вместо использования итерации, ограничения и затем отображения?

EDIT: Таким образом, основной смысл здесь: Как можно вычислить количество колеровочных номеров, как только один из чисел треугольника превышает 100? Обычно я бы написать это следующим образом:

ArrayList<Integer> triangles = new ArrayList<>(); 
for (int n=1;true;n++) { 
    int num = (n*n+n)/2; 

    if (num>100) break; 

    triangles.add(num); 
} 

, который останавливается, как только число треугольника превышает 100, который является очень эффективным; как я могу сохранить эту эффективность в лямбда-выражении?

+2

'Stream.iterate (1, n-> n + 1) .limit (100)' можно переписать как «IntStream.rangeClosed (1, 100)», что, вероятно, более читаемо. – Pshemo

+0

Почему вы используете как предел, так и фильтр?Я считаю, что второй фильтр ограничит вывод на основе расчета, поэтому вы получите только результаты, которые меньше 100, а не меньше 100. –

+0

В чем смысл? Или это просто любопытство? – doublep

ответ

6

В общем случае то, что вы ищете, занимает время. К сожалению, у него нет реализации по умолчанию в потоках Java 8. См. question about take-while.

+3

Это работает для Java 9. –

-2

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

List<Integer> l = IntStream.rangeClosed(1, 100) 
      .mapToObj(n -> (n*n + n)/2) 
      .collect(Collectors.toList()); 

примитивными потока оберток нужен дополнительный шаг вверх-преобразования к объектам, следовательно, метод mapToObj.

Если вы хотите, чтобы остановить фильтрацию, когда вы нажмете 100, самый простой способ, которым я могу думать

IntFunction<Integer> calc =n -> (n*n+n)/2; 
    List<Integer> l = IntStream.rangeClosed(1, 100) 
      .filter(n -> calc.apply(n) < 100) 
      .mapToObj(calc) 
      .collect(Collectors.toList()); 

на основе изменений в ваш вопрос, я думаю, что это тоже очень важно отметить. Если вы хотите, чтобы отразить то, что вы привыкли делать, что будет выглядеть следующим образом:

List<Integer> results = new ArrayList<>(100); 
    IntStream.rangeClosed(1, 100).forEach(i -> { 
     int tri =calc.apply(i); 
     if(tri < 100) { 
      results.add(tri); 
     } 
    }); 

Стоит отметить, что потоки не обязательно упорядоченные (хотя реализация по умолчанию следует итератору). Если бы это было преобразовано в параллельный поток, вы увидели бы разницу (и мощность потоков). Вы не можете отказаться от выполнения, потому что тогда вы принимаете определенную сумму в отношении порядка обработки. Отфильтровывая ранние (в моей второй форме), вы убедитесь, что в итоге вы получите итоговый поток из 13 записей в нем до окончательного расчета. Возьмите этот параллельный вариант как примечание.

List<Integer> l = IntStream.rangeClosed(1, 100).parallel() 
      .filter(n -> calc.apply(n) < 100) 
      .mapToObj(calc) 
      .collect(Collectors.toList()); 

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

+1

ОП задает вопрос о том, как остановить потоковое вещание, когда значение '(n * n + n)/2' начнет становиться больше 100, из-за большого количества случаев, которые необходимо будет отфильтровать. Поэтому вопрос заключается в том, «если мы знаем, что значения после некоторого n-го значения не понадобятся, как мы можем пропустить их». – Pshemo

+0

Op еще не ответил на все вопросы. Пока неясно, о чем он просит. –

+3

@JohnAment, если вам непонятно, в чем вопрос, это хорошая причина не отвечать. –