Firstly, this is going to sound like homework, but it ain't. Just a problem I'm trying to solve at work.
I have a list of objects, the objects have a sequence number which indicates their order in the list in the UI. Example:
public class Task {
Long id;
String name;
Long seq;
}
The table in my UI has "up" and "down" links on each row of the table for moving the tasks up and down in the list.
I'm implementing two methods to handle the reordering. These methods are call by ajax in the web UI.
public void incTaskSeq(List<Task> allTasks, Task taskToMove)
For example; if I have t1.seq=1, t2.seq=2, t3.seq=3, t4.seq=4, t5.seq=5 and I want to increment the place of t3, then t3.seq becomes 4, and t4.seq must become 3.
public void decTaskSeq(List<Task> allTasks, Task taskToMove)
Similarly; if I have t1.seq=1, t2.seq=2, t4.seq=3, t3.seq=4, t5.seq=5 and I want to decrement the place of t4, then t4.seq becomes 2, and t2.seq must become 3. Resulting in:
t1.seq=1, t4.seq=2, t2.seq=3, t3.seq=4, t5.seq=5
I'm a little stuck on the best way to do this.
I was thinking of putting all the tasks in a HashMap and then sort the map by the sequence number. Then locate the taskToMove in the map, change the sequence number, and then change all the affected tasks sequences.
But this approach seems inelegant. Does anyone have any ideas how I should do this?
Thanks, Rob
Use a Comparator, which is the Java interface for sorting non-naturally.
public TaskSequenceComparator implements Comparator<Task> {
public int compare(Task one, Task two) {
return one.getSequence() - two.getSequence();
}
}
...
List<Task> tasks = ...;
Collections.sort(tasks, new TaskSquenceComaprator());
// tasks is now sorted by sequence.
You can create multiple Comparator classes to implement each kind of supported sort. Then you can select from them when you need the list sorted in a particular manner.
Implement a Comparator for each criteria you want to sort for.
Create a new ordered Collection object (maybe a TreeSet) passing it the Comparator needed. Do .addAll of the objects.
Just let the List keep tarck of ordering. (Except You always need to update the seqence number).
public void incTaskSeq(List<Task> allTasks, Task taskToMove){
int movTaskNum = 0;
for(int i=0;i<allTasks.size();i++){
if(allTasks.get(i).equals(taskToMove))
movTaskNum = i;
}
allTasks.remove(taskToMove);
allTasks.add(i-1, taskToMove);
}
sorry for typos
Use a doubly linked list and swap the sequence numbers when you move an item.
Related
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 2 classes:
public class ChatGroup{
final public String name;
private List<ChatContact> contacts;
/* ---getters/setters/constructors-- */
}
public class ChatContact implements Parcelable, Comparable {
final public String name;
final public String jid;
public Status status;
/* ---getters/setters/constructors-- */
}
Then I have a list of ChatGroup items:
List<ChatGroup> chatGroupList = .....;
As you can see every ChatGroup has a list of ChatContact., and what I need is to search inside chatGroupsList, for ChatContacts that matches a query (search by username).
A way I'm doing, is do an auxilar list, search for every group, and look "inside" for ever chatContact, if exist I add the group with the contact:
private List<ChatGroup> searchContacts(String query) {
List<ChatGroup> filteredContacts = new ArrayList<>();
for (ChatGroup chatGroup : chatGroupList) {
ChatGroup auxChatGroup = new ChatGroup(chatGroup.name);
for (ChatContact chatContact : chatGroup.getContacts()) {
if (chatContact.name.toLowerCase().contains(query)) {
auxChatGroup.addContact(chatContact);
}
}
if (auxChatGroup.getContacts().size() > 0)
filteredContacts.add(auxChatGroup);
}
for (ChatGroup chatGroup : filteredContacts) {
Collections.sort(chatGroup.getContacts());
}
return filteredContacts;
}
All of this works perfect. But right now, this list has few groups with few contacts each one, but in a future will be a high number of elements, and this could be a "slow" solution.
So my question is, there is another faster way to do this type of search?
Unfortunately, if you are seriously going to search for something like "a" and want everyone who has the letter A at any point in their name, that type of search does not index well.
But looking at your algorithm, I see a few possible improvements.
Initialize ChatGroup auxChatGroup = null and only create the object when you find a result that matches the filter. This will avoid creating a few unnecessary objects if you have lots of rooms.
Sorting the list of contacts every time you do a search seems like a lot of wasted effort. Using a sorted collection such as TreeSet could offer you a huge time savings on each search.
If the number of groups becomes huge, as in millions, then consider using a multi-threaded search.
Depending on your use case, it may be possible to return a filtered "view" instead of a snapshot. However that may add some complexity and possible gotchas.
I am implementing a BFS on a graph, where nodes are marked by objects of a State class (I have implemented an implicit equals to method for comparison).
I have implemented my queue using a PriorityQueue with a comparator that returns 1 since I want to expand the program to handle DFS, Astar etc, which I can do by just changing the logic inside the comparator
Here is the relevant code:
//BFSComparator.java
import java.util.Comparator;
public class BFSComparator implements Comparator<State>{
#Override public int compare(State x, State y) {
return 1;
}
}
//solver.java
Comparator comparator = new BFSComparator();
PriorityQueue<State> frontierList = new PriorityQueue<State>(500,comparator); //List of nodes to be expanded
frontierList.add(seed state0);
while (!frontierList.isEmpty()){
curState = frontierList.poll();
//handle, expand and add child states to frontierList
While iterating through the list and printing elements present, I found that some elements do not move up the rank (example, {a,b,c,d,e} on poll becomes {b,e,c,d} on poll() rather than {b,c,d,e}), and hence, it does not perform FIFO.
for(State x:frontierList) {
//print x
}
1) Is there something wrong with my comparator?
2) Is there a better way to do this generically? i.e. , a better Container than priority queue that I can just add to while changing the logic behind the sorting rather than use Queues and stacks with difference call names like push and pop? This would be helpful when I sort them later based on heuristics. Or should I just use a linked list and perform an insertion sort based approach?
EDIT:
I'd like to make it a little more clear. I'm trying to implement a collection that I can throw things at with a common add(State) or State x = remove() irrespective of DFS or BFS (FIFO or LIFO) or other priority based algorithms like A-Star and Beam Search.
I'm probably going to extend collection and implement add and other methods.
public int compare(State x, State y)
This method return a positive value means x > y, a negative value means x < y and 0 means x==y.
I thouht you should use Queue to declare frontierList instead
When you need DFS, use LinkedList<State>
When you need BFS, use PriorityQueue<State> and a Comparator<State> return the min or max State you want
I have some events, where each of them has a probability to happen, and a weight if they do. I want to create all possible combinations of probabilities of events, with the corresponding weights. In the end, I need them sorted in weight order. It is like generating a probability tree, but I only care about the resulting leaves, not which nodes it took to get them. I don't need to look up specific entries during the creation of the end result, just to create all the values and sort them by weight.
There will be only about 5-15 events,but since there is 2^n resulting possibilities with n events, and this is to be done very often, I don’t want it to take unnecessarily long time. Speed is much more important than the amount of storage used.
The solution I came up with works but is slow. Any idea for a quicker solution or some ideas for improvement?
class ProbWeight {
double prob;
double eventWeight;
public ProbWeight(double aProb, double aeventWeight) {
prob = aProb;
eventWeight = aeventWeight;
}
public ProbWeight(ProbWeight aCellProb) {
prob = aCellProb.getProb();
eventWeight = aCellProb.geteventWeight();
}
public double getProb(){
return prob;
}
public double geteventWeight(){
return eventWeight;
}
public void doesHappen(ProbWeight aProb) {
prob*=aProb.getProb();
eventWeight += aProb.geteventWeight();
}
public void doesNotHappen(ProbWeight aProb) {
prob*=(1-aProb.getProb());
}
}
//Data generation for testing
List<ProbWeight> dataList = new ArrayList<ProbWeight>();
for (int i =0; i<5; i++){
ProbWeight prob = new ProbWeight(Math.random(), 10*Math.random(), i);
dataList.add(prob);
}
//The list where the results will end up
List<ProbWeight> resultingProbList = new ArrayList<ProbWeight>();
// a temporaty list to avoid modifying a list while looping through it
List<ProbWeight> tempList = new ArrayList<ProbWeight>();
resultingProbList.add(dataList.remove(0));
for (ProbWeight data : dataList){ //for each event
//go through the already created event combinations and create two new for each
for(ProbWeight listed: resultingProbList){
ProbWeight firstPossibility = new ProbWeight(listed);
ProbWeight secondPossibility = new ProbWeight(listed);
firstPossibility.doesHappen(data);
secondPossibility.doesNotHappen(data);
tempList.add(firstPossibility);
tempList.add(secondPossibility);
}
resultingProbList = new ArrayList<ProbWeight>(tempList);
}
// Then sort the list by weight using sort and a comparator
It is 50% about choosing an appropriate data structure and 50% about the algorithm. Data structure - I believe TreeBidiMap will do the magic for you. You will need to implement 2 Comparators - 1 for the weight and another for the probability.
Algorithm - trivial.
Good luck!
just a few tricks to try to speed up your code:
- try to avoid non necessary objects allocation
- try to use the right constructor for your collections , in your code sample it seems that you already know the size of the collections, so use it as a parameter in the constructors to prevent useless collections resizing (and gc calls)
You may try to use a Set instead of List in order to see the ordering made on the fly.....
HTH
jerome
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