Вы можете свернуть свой собственный вариант Stream
, обернув свою лямбда, чтобы выбросить исключенное исключение, а затем позже разблокировать это исключенное исключение в операциях терминала:
@FunctionalInterface
public interface ThrowingPredicate {
public boolean test(T t) throws X;
}
@FunctionalInterface
public interface ThrowingFunction {
public R apply(T t) throws X;
}
@FunctionalInterface
public interface ThrowingSupplier {
public R get() throws X;
}
public interface ThrowingStream {
public ThrowingStream filter(
ThrowingPredicate super T, ? extends X> predicate);
public ThrowingStream map(
ThrowingFunction super T, ? extends R, ? extends X> mapper);
public R collect(Collector super T, A, R> collector) throws X;
// etc
}
class StreamAdapter implements ThrowingStream {
private static class AdapterException extends RuntimeException {
public AdapterException(Throwable cause) {
super(cause);
}
}
private final Stream delegate;
private final Class x;
StreamAdapter(Stream delegate, Class x) {
this.delegate = delegate;
this.x = x;
}
private R maskException(ThrowingSupplier method) {
try {
return method.get();
} catch (Throwable t) {
if (x.isInstance(t)) {
throw new AdapterException(t);
} else {
throw t;
}
}
}
@Override
public ThrowingStream filter(ThrowingPredicate predicate) {
return new StreamAdapter<>(
delegate.filter(t -> maskException(() -> predicate.test(t))), x);
}
@Override
public ThrowingStream map(ThrowingFunction mapper) {
return new StreamAdapter<>(
delegate.map(t -> maskException(() -> mapper.apply(t))), x);
}
private R unmaskException(Supplier method) throws X {
try {
return method.get();
} catch (AdapterException e) {
throw x.cast(e.getCause());
}
}
@Override
public R collect(Collector collector) throws X {
return unmaskException(() -> delegate.collect(collector));
}
}
. Тогда вы можете использовать это же точный способ как Stream
:
Stream s = accounts.values().stream();
ThrowingStream ts = new StreamAdapter<>(s, IOException.class);
return ts.filter(Account::isActive).map(Account::getNumber).collect(toSet());
Это решение потребует довольно много шаблонов, поэтому я предлагаю вам взглянуть на библиотеку , которую я уже сделал , что делает именно то, что я описал здесь для всего класса Stream
(и более!).
Вот как подавить предупреждения:
mean, nanmean и warning: Среднее значение пустого среза
In [528]: import warnings
In [530]: x = np.array([0,1,2],float)
In [531]: y = np.array([np.inf,3,2],float)
In [532]: np.outer(x,y)
/usr/local/lib/python3.5/dist-packages/numpy/core/numeric.py:1093: RuntimeWarning: invalid value encountered in multiply
return multiply(a.ravel()[:, newaxis], b.ravel()[newaxis,:], out)
Out[532]:
array([[ nan, 0., 0.],
[ inf, 3., 2.],
[ inf, 6., 4.]])
In [535]: with warnings.catch_warnings():
...: warnings.simplefilter('ignore',category=RuntimeWarning)
...: z = np.outer(x,y)
...:
In [536]: z
Out[536]:
array([[ nan, 0., 0.],
[ inf, 3., 2.],
[ inf, 6., 4.]])
заменить nan
на 1
:
In [542]: z[np.isnan(z)]=1
In [543]: z
Out[543]:
array([[ 1., 0., 0.],
[ inf, 3., 2.],
[ inf, 6., 4.]])
In [547]: z[np.isinf(z)]=9999
In [548]: z
Out[548]:
array([[ 1.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[ 9.99900000e+03, 3.00000000e+00, 2.00000000e+00],
[ 9.99900000e+03, 6.00000000e+00, 4.00000000e+00]])
===========================
Мы могли бы создать mask
, используя тип тестирования что @P-robot
демонстрирует:
In [570]: np.outer(np.isinf(x),y==0)|np.outer(x==0,np.isinf(y))
Out[570]:
array([[ True, False, False],
[False, False, False],
[False, False, False]], dtype=bool)
In [571]: mask=np.outer(np.isinf(x),y==0)|np.outer(x==0,np.isinf(y))
In [572]: with warnings.catch_warnings():
...: warnings.simplefilter('ignore',category=RuntimeWarning)
...: z = np.outer(x,y)
...:
In [573]: z[mask]=1
In [574]: z
Out[574]:
array([[ 1., 0., 0.],
[ inf, 3., 2.],
[ inf, 6., 4.]])
Или с более грязными входами:
In [587]: x = np.array([0,1,2,np.inf],float)
In [588]: y = np.array([np.inf,3,np.nan,0],float)
In [589]: mask=np.outer(np.isinf(x),y==0)|np.outer(x==0,np.isinf(y))
...
In [591]: with warnings.catch_warnings():
...: warnings.simplefilter('ignore',category=RuntimeWarning)
...: z = np.outer(x,y)
...:
In [592]: z[mask]=1
In [593]: z
Out[593]:
array([[ 1., 0., nan, 0.],
[ inf, 3., nan, 0.],
[ inf, 6., nan, 0.],
[ inf, inf, nan, 1.]])
Одно из решений может заключаться в том, чтобы избежать использования np.multiply.outer
и найти решение, используя умножение по типу на матрицах, которые уже были проверены, чтобы увидеть, соответствуют ли они интересующему условию (ноль в одном массиве, inf
в другом массиве ).
import numpy as np
A = np.array([0., 0., 0.4, 2])
B = np.array([float('inf'), 1., 3.4, np.inf])
# Conditions of interest
c1 = (A == 0)
c2 = (B == np.inf)
condition1 = np.multiply.outer(c1, c2)
c3 = (A == np.inf)
c4 = (B == 0)
condition2 = np.multiply.outer(c3, c4)
condition = condition1 | condition2
AA = np.multiply.outer(A, np.ones(B.shape))
BB = np.multiply.outer(np.ones(A.shape), B)
AA[condition] = 0.
BB[condition] = 0.
AA*BB
Однако это может не соответствовать запросу «эффективности» плаката.
Нужно ли беспокоиться о других источниках значений nan
? Если нет, вы всегда можете просто исправить это на отдельном шаге:
import numpy as np
r = np.multiply.outer([0.], [float('inf')])
np.where(np.isnan(r), 0, r)
До вас, если вы хотите подавить предупреждения.
Хотя я согласен с ответом @ ShadowRanger, дешевым взломом может воспользоваться np.nan_to_num , который заменяет infs большими конечными числами, которые затем передадут вам inf * 0 = 0.
Чтобы преобразовать ненужные оставшиеся высокие конечные числа обратно в inf (учитывая некоторые другие операции помимо вашего вопроса), вы можете использовать несколько больших чисел на что угодно> 1, а затем разделить на одну и ту же сумму (чтобы не влиять другие номера). Например:
In [1]: np.nan_to_num(np.inf)
Out[1]: 1.7976931348623157e+308
In [2]: np.nan_to_num(np.inf)*1.1
RuntimeWarning: overflow encountered in double_scalars
Out[2]: inf
In [3]: np.nan_to_num(np.inf)*1.1/1.1
RuntimeWarning: overflow encountered in double_scalars
Out[3]: inf
Перед потоком downvotes это явно не лучшая практика и потенциально может иметь побочные эффекты в зависимости от вашего варианта использования, но просто подумал, что я выбрал бы альтернативу.
@P-robot's
. – hpaulj 10 December 2016 в 19:06