не кидайтесь тапками плиз, превратилась совсем в говнокодершу. может, старость.
есть такой код:
for (ListIterator<Double> it = list.listIterator(); it.hasNext(); ) {
Double value = it.next();
Double refValue = null;
if (value != 0) {
if (value < 0 && it.hasNext()) {
refValue = it.next();
it.previous();
} else if (value > 0 && it.hasPrevious()) {
it.previous();
refValue = it.previous();
it.next();
it.next();
}
}
... //какие-то операции с value и refValue
}
што он делает — проходится по отсортированному списку из чисел (вида -100, -90, -2, 0, 3, 50) , и для каждого из чисел (кроме центрального — 0) находит "пару" — в зависимости оттого если число отрицательное или положительное — это или следующее число в списке, либо предыдущее. ноля быть не может. зачем такое надо не спрашивайте !!
вопрос — как переписать этот уродский код чтоб было красивее. одобряется использование фич джавы 8 — если они тут подойдут
Здравствуйте, зиг, Вы писали:
зиг>вопрос — как переписать этот уродский код чтоб было красивее. одобряется использование фич джавы 8 — если они тут подойдут
java8 стримы работают с текущим значением, там нет "предыдущего" и "следующего", так, что я бы даже отказался от итераторов. Не сказал бы, что короче, но на мой вкус читабельнее:
public static void main(String... args) {
List<Integer> ints = Arrays.asList(-100, -90, -2, 0, 3, 50);
for(int i = 0; i != ints.size(); ++i) {
Integer value = ints.get(i);
Integer refVal = getRefVal(value,
i != 0 ? ints.get(i-1) : null,
i != ints.size()-1 ? ints.get(i+1) : null);
System.out.println("value: " + value + ", refVal: " + refVal);
}
}
private static Integer getRefVal(Integer cur, Integer prev, Integer next) {
Integer result = null;
if ( cur < 0 && next != null ) {
result = next;
} else if ( cur > 0 && prev != null ) {
result = prev;
}
return result;
}
Здравствуйте, Stanislav V. Zudin, Вы писали:
SVZ>ИМХО из всех предложенных вариантов твой — самый читабельный. SVZ>Оставь как есть.
Читаемым он бы был, если бы не куча проверок на пограничные условия.
Здравствуйте, зиг, Вы писали:
зиг>што он делает — проходится по отсортированному списку из чисел (вида -100, -90, -2, 0, 3, 50) , и для каждого из чисел (кроме центрального — 0) находит "пару" — в зависимости оттого если число отрицательное или положительное — это или следующее число в списке, либо предыдущее. ноля быть не может. зачем такое надо не спрашивайте !!
зиг>вопрос — как переписать этот уродский код чтоб было красивее. одобряется использование фич джавы 8 — если они тут подойдут
А так нельзя?
int ap=0; double[] ac=new double[2];
for (ListIterator<Double> it = list.listIterator(); it.hasNext(); ac[0]=ac[1]) {
ac[ap]=it.next(); if (ap<1) { ap=1; continue; }
if (ac[1]<0) output(ac[1],ac[0]);
if (ac[0]>0) output(ac[0],ac[1]);
}
Здравствуйте, Blazkowicz, Вы писали:
B>Здравствуйте, Stanislav V. Zudin, Вы писали:
SVZ>>ИМХО из всех предложенных вариантов твой — самый читабельный. SVZ>>Оставь как есть. B>Читаемым он бы был, если бы не куча проверок на пограничные условия.
Меня скорее все эти next() & prev() в разных последовательностях заставляют немного напрячься.
Здравствуйте, зиг, Вы писали:
зиг>есть такой код:
Этот код, кстати, падает если входной массив содержит только положительные числа. Это так и должно быть??
Я бы написал тупо как есть:
private static void doStuff(final List<Double> list) {
Double previous = null;
for (final ListIterator<Double> it = list.listIterator(); it.hasNext(); ) {
final Double value = it.next();
final Double refValue;
if (value < 0) {
refValue = peekNext(it);
} else if (value > 0) {
refValue = previous;
} else {
refValue = null;
}
previous = value;
... //какие-то операции с value и refValue
}
}
private static Double peekNext(final ListIterator<Double> it) {
if(!it.hasNext()) return null;
final Double val = it.next();
it.previous();
return val;
}
Этот код, кстати, не падает.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Предполагаю, что у нас вначале не итератор, а коллекция, и дополнительно добавил граничные условия.
По существу здесь 4 метода:
1) преобразование из итератора в коллекцию с нормальными граничными условиями (в конце null чтоб не делать дополнительный if). Это не писал, ибо лень;
2) Из этой коллекции возвращаю пары value — refValue. В качестве пар заюзал обычный массив, в других языках вернул бы кортеж или пару как тип. Причем вернул как стрим, он ленивый;
3) Вычисление refvalue в отдельный метод вынес — тоже можно тестить отдельно;
3) собственно сама логика, которая выполняет сейчас только печать.
Строчек кода больше, но зато здесь следование single responsibility principle и каждый из методов можно тестить по отдельности, если б я сделал их публичными.
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Stream;
public class Test {
public static void main(String[] args) {
//Это пример, в исходном примере там итератор, потому лучше из этого итератора собрать какой то Collection
Collection<Double> list = Arrays.asList(-100.0, -90.0, -2.0, 0.0, 3.0, 50.0, null);
Stream<Double[]> pairStream = getValueToRefValueStream(list);
processStream(pairStream);
}
private static Stream<Double[]> getValueToRefValueStream(Collection<Double> list) {
Iterator<Double> it = list.iterator();
if (!it.hasNext()) {
return Stream.empty();
}
final AtomicReference<Double> pvRef = new AtomicReference<>(null);
final AtomicReference<Double> cvRef = new AtomicReference<>(it.next());
Stream<Optional<Double[]>> optionalStr = list
.stream()
.skip(1)
.map( (Double plus1) -> {
Double minus1 = pvRef.get();
Double value = cvRef.get();
pvRef.set(cvRef.get());
cvRef.set(plus1);
Double refValue = calculateRefValue(plus1, minus1, value);
if (refValue != null) {
return Optional.of(new Double[]{value, refValue});
}
return Optional.empty();
});
return optionalStr.filter(Optional::isPresent).map(Optional::get);
}
private static Double calculateRefValue(Double plus1, Double minus1, Double value) {
Double result = null;
if (value != null && value != 0) {
if (value < 0) {
result = plus1;
} else if (value > 0) {
result = minus1;
}
}
return result;
}
private static void processStream(Stream<Double[]> pairStream) {
//какие-то операции с value и refValue
pairStream.forEach( a -> {
Double value = a[0];
Double refValue = a[1];
System.out.print(value);
System.out.print(":");
System.out.println(refValue);
});
}
}
PS Больше года не пишу на Java — сейчас Java синтаксис кажется ужас. Для простейших действий до черта строк кода, и велика вероятность ошибиться. Пипец, если из вакансий останется только Java и я не смогу найти работу на нормальных языках, придется на пенсию поход скоро уходить.
E>Строчек кода больше, но зато здесь следование single responsibility principle и каждый из методов можно тестить по отдельности, если б я сделал их публичными.
CS>Double pv, cv;
CS>for (ListIterator<Double> it = list.listIterator(); it.hasNext(); ) {
CS> pv = cv;
CS> cv = it.next();
CS> Double rv;
CS> if (pv != null && cv != 0) {
CS> if (cv < 0)
CS> rv = pv;
CS> else if (cv > 0)
CS> rv = cv;
CS> }
CS> ... //какие-то операции с value и refValue
CS>}
CS>
CS> ... //какие-то операции с value и refValue
А где само value-то? сv? Я так понял по условию refValue всегда != value. Оно или null или prev или next.
Здравствуйте, зиг, Вы писали:
зиг>што он делает — проходится по отсортированному списку из чисел (вида -100, -90, -2, 0, 3, 50) , и для каждого из чисел (кроме центрального — 0) находит "пару" — в зависимости оттого если число отрицательное или положительное — это или следующее число в списке, либо предыдущее. ноля быть не может. зачем такое надо не спрашивайте !!
Формально он и для нулевых элементов что-то делает (при value == 0, refVal == null).
Плюс ещё валится, если самый первый валуй позитивный, совершенно напрасно спрашивая при этом it.hasPrevious(), который всегда вернёт труё, ибо только что взяли же следующий.
Если не надо валиться и не надо ничего делать для текущего нуля, то можно как-то так
Правда при этом на одной итерации может понадобиться дважды звать обработку, за себя и за того парня, поэтому лучше её вынести в отдельную функцию. Ещё могут быть какие-то тонкие отличия ввиду того, что зачем-то обрабатываются объекты (ака пойнтеры на них), но сами объекты вроде немодифицируемые, пойнтера мы передадим в функцию, которая их (локальные) испортить не сможет, а порядок обработки должен сохраняться. Зато движение по списку строго одностороннее.
зиг>вопрос — как переписать этот уродский код чтоб было красивее. одобряется использование фич джавы 8 — если они тут подойдут
зиг>спасибо
Здравствуйте, StanislavK, Вы писали:
SK>А где само value-то? сv? Я так понял по условию refValue всегда != value. Оно или null или prev или next.
Как-то так:
Double pv, cv;
for (ListIterator<Double> it = list.listIterator(); it.hasNext(); ) {
pv = cv;
cv = it.next();
Double refValue;
Double value;
if (pv != null && cv != 0) {
if (cv < 0) { refValue = pv; value = cv; }
else if (cv > 0) { refValue = cv; value = pv; }
}
... //какие-то операции с value и refValue
}
TL;DR: смысл в том что есть sliding window из двух элементов. В зависимости от "стороны от нуля" один из этих элементов refValue, а второй value. И наоборот.
B> private static class Triad<T> {
B> public Triad(T ... triad) {
B> this.triad = triad;
B> }
B>
По сути это Zipper (который из ФП). Класс Triad надо сделать враппером вокруг итератора. И назвать его что-то типа ListIteratorZipper(ListIterator it).