class Note{
private text;
..
private int score = 0;
}
class Project{
...
List<Note> notes;
private int score = 0;
}
Project score is derived by project properties + sum of note scores.
First I'm updating and replacing all notes in the project. Then iterating again to sum the note score.
project.notes(project.notes()
.stream()
.map(this::updateNote)
.collect(Collectors.toList()));
project.score(project.notes()
.stream()
.mapToInt(n->n.score())
.sum());
private Note updateNote(Note note){
note.score(....);
return note;
}
Somehow I feel this is not right. Is there an elegant solution to avoid looping twice?
Performing a side-effect-ful method in a map operation like this is suspect no matter how you want to slice this puzzle, it's always going to look a bit weird.
You're abusing map here: You map objects to itself, but in so doing, cause a side effect. well, in for a penny, in for a pound, I guess - that is the suspect thing here, but the code works (it's just bad style). Note also that passing the collected list to project.notes does nothing, just project.notes().stream().map(this::updateNote).collect(Collectors.toList()) and letting the collection be lost to the either already 'works'. The only point of collecting is merely to force the stream to actually iterate (map doesn't cause iteration, it merely says: When you start iterating, map as-you-go).
So:
project.notes()
.stream()
.map(this::updateNote)) // no-op streamwise. Just making the side effect happen
.mapToInt(this::score)
.sum();
is all you need - but it's.. still a bit stinky. If instead of updateNote, note was immutable and there is a calculateScore method, you could do:
project.notes()
.stream()
.mapToInt(this::calculateScore)
.sum()
Here, calculateScore doesn't change anything about a Note object, it merely.. calculates the score and returns it, without changing any fields.
EDIT: I forgot a 'stream' in stream, and added a clarification.
You may get rid of looping twice by accumulating the sum in an AtomicInteger, but this would result in replacing the method reference this::updateNote with a lambda:
AtomicInteger sum = new AtomicInteger(0);
project.notes(project.notes()
.stream()
.map(note -> {
Note updated = updateNote(note);
sum.addAndGet(updated.getScore());
return updated;
})
.collect(Collectors.toList()));
project.score(sum.intValue());
Related
My classes.
class MyLoan {
private Long loanId;
private BigDecimal loanAmount;
private BigDecimal totalPaid;
....
}
class Customer {
private Long loanId;
private List<MyLoan> myLoan;
}
I want to iterate over the myLoan from a Customer and calculate the totalPaid amount.
My logic is "If loanId is 23491L or 23492L, then add the loanAmount of those two loanId's and set the value in the totalPaid amount of loanId 23490L".totalPaid amount is always showing as zero with my logic below.
And want to use Java 8 streams, but unable to write multiple conditions when using streams.
BigDecimal spreadAmount;
for (MyLoan myloan: customer.getMyLoan()) {
if (myloan.getLoanId() == 23491L || myloan.getLoanId() == 23492L) {
spreadAmount = spreadAmount.add(myloan.getLoanAmount());
}
if (myloan.getLoanId() == 23490L) {
myloan.setTotalPaid(spreadAmount);
}
}
The totalPaid field is not modified because your MyLoan instance with id 23490l is encountered before the other two MyLoans.
As #Silvio Mayolo has suggested in the comments you should first compute the total amount with a temp variable and then assign it to the totalPaid field of the MyLoan instance with id 23490l.
This is a stream implementation of what you were trying to do:
//If to make sure that the element MyLoan invoking the setter is actually present
if (myLoan.stream().map(MyLoan::getLoanId).anyMatch(value -> value == 23490l)){
myLoan.stream()
.filter(loan -> loan.getLoanId() == 23490l)
.findFirst()
.get()
.setTotalPaid(myLoan.stream()
.filter(loan -> loan.getLoanId() == 23491l || loan.getLoanId() == 23492l)
.map(MyLoan::getLoanAmount)
.reduce(BigDecimal.valueOf(0), (a, b) -> a = a.add(b)));
}
WARNING
The method get(), invoked on the Optional retrieved with the terminal operation findFirst(), could throw a NoSuchElementException if a MyLoan with id 23490l is not present within the list. You should first make sure that the element is present, as I've done with my if statement.
A second (bad practice) could involve catching the NoSuchElementException thrown by the get(), in case the desired MyLoan is not present. As it has been pointed out in the comments, catching a RuntimeException (NoSuchElementException is a subclass of it) is a bad practice, as we should investigate on the origin of the problem rather than simply catching the exception. This second approach was honestly a (lazy) last resort only to show another possible way of handling the case.
Firstly, you need to fetch a loan for which you want to define a total paid amount. If this step succeeds, then calculate a total.
In order to find a loan with a particular id using streams, you need to create a stream over the customers loans and apply filter() in conjunction with findFirst() on it. It'll give you the first element from the stream that matches the predicate passed into the filter. Because result might not be present in the stream, findFirst() returns an Optional object.
Optional class offers a wide range of method to interact with it like orElse(), ifPresent(), orElse(), etc. Avoid blindly using get(), unless you didn't check that value is present, which is in many cases isn't the most convenient way to deal with it. Like in the code below, ifPresent() is being used to proceed with the logic if value is present.
So if the required loan was found, the next step is to calculate the total. Which is done by filtering out target ids, extracting amount by applying map() and adding the amounts together using reduce() as a terminal operation.
public static void setTotalPaid(Customer customer, Long idToSet, Long... idsToSumUp) {
List<MyLoan> loans = customer.getMyLoan();
getLoanById(loans, idToSet).ifPresent(loan -> loan.setTotalPaid(getTotalPaid(loans, idsToSumUp)));
}
public static Optional<MyLoan> getLoanById(List<MyLoan> loans, Long id) {
return loans.stream()
.filter(loan -> loan.getLoanId().equals(id))
.findFirst();
}
public static BigDecimal getTotalPaid(List<MyLoan> loans, Long... ids) {
Set<Long> targetLoans = Set.of(ids); // wrapping with set to improve performance
return loans.stream()
.filter(loan -> targetLoans.contains(loan.getLoanId()))
.map(MyLoan::getLoanAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
Here is my Java code:
static Map<BigInteger, Integer> cache = new ConcurrentHashMap<>();
static Integer minFinder(BigInteger num) {
if (num.equals(BigInteger.ONE)) {
return 0;
}
if (num.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) {
//focus on stuff thats happening inside this block, since with given inputs it won't reach last return
return 1 + cache.computeIfAbsent(num.divide(BigInteger.valueOf(2)),
n -> minFinder(n));
}
return 1 + Math.min(cache.computeIfAbsent(num.subtract(BigInteger.ONE), n -> minFinder(n)),
cache.computeIfAbsent(num.add(BigInteger.ONE), n -> minFinder(n)));
}
I tried to memoize a function that returns a minimum number of actions such as division by 2, subtract by one or add one.
The problem I'm facing is when I call it with smaller inputs such as:
minFinder(new BigInteger("32"))
it works, but with bigger values like:
minFinder(new BigInteger("64"))
It throws a Recursive Update exception.
Is there any way to increase recursion size to prevent this exception or any other way to solve this?
From the API docs of Map.computeIfAbsent():
The mapping function should not modify this map during computation.
The API docs of ConcurrentHashMap.computeIfAbsent() make that stronger:
The mapping function must not modify this map during computation.
(Emphasis added)
You are violating that by using your minFinder() method as the mapping function. That it seems nevertheless to work for certain inputs is irrelevant. You need to find a different way to achieve what you're after.
Is there any way to increase recursion size to prevent this exception or any other way to solve this?
You could avoid computeIfAbsent() and instead do the same thing the old-school way:
BigInteger halfNum = num.divide(BigInteger.valueOf(2));
BigInteger cachedValue = cache.get(halfNum);
if (cachedValue == null) {
cachedValue = minFinder(halfNum);
cache.put(halfNum, cachedValue);
}
return 1 + cachedValue;
But that's not going to be sufficient if the computation loops. You could perhaps detect that by putting a sentinel value into the map before you recurse, so that you can recognize loops.
I'm learning Java for the first time (my prior experience is Python and Haskell). I have a situation that would, in Python, require a "decorate and sort" idiom. Such as the following (code not tested but this is roughly correct):
origList = <something>
decorated = sorted( [(evalFunc(item), item) for item in origList] )
finalList = [item for _, item in decorated]
By choosing a different evalFunc you can choose how this is sorted.
In Java, I'm writing a program that composes music by choosing from among a list of notes, evaluating the "fitness" of each note, and picking the best. I have a class representing musical notes:
class Note {
...
}
I have a class that represents the fitness of a note as two values, its goodness and badness (yes, these are separate concepts in my program). Note: in Python or Haskell, this would simply be a 2-tuple, but my understanding is that Java doesn't have tuples in the usual sense. I could make it a pair, but it gets unwieldy to declare variables all over the place like List<Pair<Type1,Pair<Type2,Type3>>>. (As an aside, I don't think Java has type aliases either, which would let me shorten the declarations.)
class Fitness {
double goodness;
double badness;
}
The function that evaluates the fitness needs access to several pieces of data other than the Note. We'll say it's part of a "Composition" class:
class Composition {
... data declared here ... ;
public Fitness evaluate(Note n) {
}
}
I'd like to be able to compare Fitness objects in numerical order. There are two ways to compare: either goodness or badness can be numerically compared, depending on the situation.
class CompareFitnessByGoodness implements Comparator<Fitness> {
}
class CompareFitnessByBadness implements Comparator<Fitness> {
}
I'd like to package the Note together with its fitness, so I can sort the combined list by fitness and later pull out the best Note.
class Together {
public Note;
public Fitness;
}
I'd like to sort a List<Together> by either the goodness, or by the badness. So I might need:
class CompareTogetherByGoodness implements Comparator<Together> {
...
}
class CompareTogetherByBadness implements Comparator<Together> {
...
}
Eventually I'll write something like
Note pickBest(List<Together> notes) {
// Pick a note that's not too bad, and pretty good at the same
// time.
// First sort in order of increasing badness, so I can choose
// the bottom half for the next stage (i.e. the half "least bad"
// notes).
Collections.sort(notes, new CompareTogetherByBadness());
List<Together> leastBadHalf = notes.subList(0, notes.size()/2);
// Now sort `leastBadHalf` and take the last note: the one with
// highest goodness.
Collections.sort(leastBadHalf, new CompareTogetherByGoodness());
return leastBadHalf.get(leastBadHalf.size()-1);
}
Whew! That is a LOT of code for something that would be a few lines in Haskell or Python. Is there a better way to do this?
EDIT:
Addressing some of the answers.
"You don't need to decorate." Well, my fitness computation is very expensive, so I want to compute it once for each note, and save the result for later access as well.
"Store goodness/badness in Note." The goodness or badness is not a property of the note alone; it's only meaningful in context and it can change. So this is a suggestion that I add mutable state which is only meaningful in some contexts, or plain wrong if there's a bug which accidentally mutates it. That's ugly, but maybe a necessary crutch for Java.
Going by what you already have
origList = <something>
decorated = sorted( [(evalFunc(item), item) for item in origList] )
finalList = [item for _, item in decorated]
This is the equivalent in modern Java:
Given your composition object:
Composition composer = ...;
And a list of notes:
List<Note> notes = ...;
Then you can do:
List<Together> notesAllTogetherNow = notes.stream()
.map(note -> new Together(note, composer.evaluate(note)))
.sorted(new CompareTogetherByGoodness())
.collect(Collectors.toList());
To get the best note, you can take a bit further:
Optional<Note> bestNote = notes.stream()
.map(note -> new Together(note, composer.evaluate(note)))
.sorted(new CompareTogetherByBadness())
.limit(notes.size() / 2) // Taking the top half
.sorted(new CompareTogetherByGoodness())
.findFirst() // Assuming the last comparator sorts in descending order
.map(Together::getNote);
You can use streams:
Function<Foo, Bar> func = ...
Comparator<Foo> comparator = ...
var list = ...
var sorted = list.stream()
.sorted(comparator)
.map(func)
.collect(Collectors.toList());
Java plainly includes a Collections.sort :: List -> Comparator -> List that does everything for you. It mutates the original list, though.
Unfortunately, Java's standard library does not include tuples and even a plain Pair; the Apache Commnons library does, though.
In short, you don't need the decorate / undecorate approach in Java.
class Fitness {
double goodness;
double badness;
}
class Together {
Note note;
Fitness fitness;
}
class Note{
}
List<Together> notes = ...
Collections.sort(notes, Comparator.comparingDouble(value -> value.fitness.badness));
List<Together> leastBadHalf = notes.subList(0, notes.size()/2);
return leastBadHalf.stream().max(Comparator.comparingDouble(value -> value.fitness.goodness));
I have a method that returns the average of a property over a number of model objects:
List<Activity> activities = ...;
double effortSum = 0;
double effortCount = 0;
activities.stream().forEach(a -> {
double effort = a.getEffort();
if (effort != Activity.NULL) {
effortCount++; < Compilation error, local variable
effortSum += effort; < Compilation error, local variable
}
});
But, the above attempt doesn't compile, as noted. The only solution that's coming to me is using an AtomicReference to a Double object, but that seems crufty, and adds a large amount of confusion to what should be a simple operation. (Or adding Guava and gaining AtomicDouble, but the same conclusion is reached.)
Is there a "best practice" strategy for modifying local variables using the new Java 8 loops?
Relevant code for Activity:
public class Activity {
public static final double NULL = Double.MIN_VALUE;
private double effort = NULL;
public void setEffort(double effort) { this.effort = effort; }
public double getEffort() { return this.effort; }
...
}
Is there a "best practice" strategy for modifying local variables using the new Java 8 loops?
Yes: don't. You can modify their properties -- though it's still a bad idea -- but you cannot modify them themselves; you can only refer to variables from inside a lambda if they are final or could be final. (AtomicDouble is indeed one solution, another is a double[1] that just serves as a holder.)
The correct way of implementing the "average" operation here is
activities.stream()
.mapToDouble(Activity::getEffort)
.filter(effort -> effort != Activity.NULL)
.average()
.getAsDouble();
In your case, there is a solution that is more functional - just compute the summary statistics from the stream from where you can grab the number of elements filtered and their sum:
DoubleSummaryStatistics stats =
activities.stream()
.mapToDouble(Activity::getEffort)
.filter(e -> e != Activity.NULL)
.summaryStatistics();
long effortCount = stats.getCount();
double effortSum = stats.getSum();
Is there a "best practice" strategy for modifying local variables
using the new Java 8 loops?
Don't try do to that. I think the main issues is that people try to translate their code using the new Java 8 features in an imperative way (like in your question - and then you have troubles!).
Try to see first if you can provide a solution which is functional (which is what the Stream API aim for, I believe).
I am looking for a data structure that operates similar to a hash table, but where the table has a size limit. When the number of items in the hash reaches the size limit, a culling function should be called to get rid of the least-retrieved key/value pairs in the table.
Here's some pseudocode of what I'm working on:
class MyClass {
private Map<Integer, Integer> cache = new HashMap<Integer, Integer>();
public int myFunc(int n) {
if(cache.containsKey(n))
return cache.get(n);
int next = . . . ; //some complicated math. guaranteed next != n.
int ret = 1 + myFunc(next);
cache.put(n, ret);
return ret;
}
}
What happens is that there are some values of n for which myFunc() will be called lots of times, but many other values of n which will only be computed once. So the cache could fill up with millions of values that are never needed again. I'd like to have a way for the cache to automatically remove elements that are not frequently retrieved.
This feels like a problem that must be solved already, but I'm not sure what the data structure is that I would use to do it efficiently. Can anyone point me in the right direction?
Update I knew this had to be an already-solved problem. It's called an LRU Cache and is easy to make by extending the LinkedHashMap class. Here is the code that incorporates the solution:
class MyClass {
private final static int SIZE_LIMIT = 1000;
private Map<Integer, Integer> cache =
new LinkedHashMap<Integer, Integer>(16, 0.75f, true) {
protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest)
{
return size() > SIZE_LIMIT;
}
};
public int myFunc(int n) {
if(cache.containsKey(n))
return cache.get(n);
int next = . . . ; //some complicated math. guaranteed next != n.
int ret = 1 + myFunc(next);
cache.put(n, ret);
return ret;
}
}
You are looking for an LRUList/Map. Check out LinkedHashMap:
The removeEldestEntry(Map.Entry) method may be overridden to impose a policy for removing stale mappings automatically when new mappings are added to the map.
Googling "LRU map" and "I'm feeling lucky" gives you this:
http://commons.apache.org/proper/commons-collections//javadocs/api-release/org/apache/commons/collections4/map/LRUMap.html
A Map implementation with a fixed
maximum size which removes the least
recently used entry if an entry is
added when full.
Sounds pretty much spot on :)
WeakHashMap will probably not do what you expect it to... read the documentation carefully and ensure that you know exactly what you from weak and strong references.
I would recommend you have a look at java.util.LinkedHashMap and use its removeEldestEntry method to maintain your cache. If your math is very resource intensive, you might want to move entries to the front whenever they are used to ensure that only unused entries fall to the end of the set.
The Adaptive Replacement Cache policy is designed to keep one-time requests from polluting your cache. This may be fancier than you're looking for, but it does directly address your "filling up with values that are never needed again".
Take a look at WeakHashMap
You probably want to implement a Least-Recently Used policy for your map. There's a simple way to do it on top of a LinkedHashMap:
http://www.roseindia.net/java/example/java/util/LRUCacheExample.shtml