Update HashMap/ArrayList passed to PriorityQueue Comparator - java

I wrote a comparator for a PriorityQueue so that it will give me the smallest value based on the first value in the ArrayList from the HashMap.
My issue is that, in the rest of my program I need to update/change those first values in the ArrayList. I'm not sure how to do that to make sure the priority queue always gives me the proper result based on the updates?
Thanks
public class MyComparator implements Comparator<Integer>{
HashMap<Integer, ArrayList<Integer>> hm;
public MyComparator(HashMap<Integer, ArrayList<Integer>> hm){
this.hm = hm;
}
#Override
public int compare (Integer num, Integer num1){
ArrayList<Integer> list = hm.get(num);
int w = list.get(0);
ArrayList<Integer> list1 = hm.get(num1);
int w1 = list1.get(0);
if(w1 - w == 0){
return 0;
}
if(w1 - w <= 0){
return 1;
}
else{
return -1;
}
}
}

If you change the value that you're using as a key in a PriorityQueue, you need to adjust the queue to reflect the change. Otherwise, your queue will potentially be in an invalid state. The data structure can't keep track of changes you make to whatever value you're using as a key. If you change the keys, you have to notify the data structure that things changed.
The queue pointedly will not re-organize itself whenever you call peek. All peek does is return the first item in the queue. The only comparison it makes is to see if the queue is empty.
The only way to re-organize a Java PriorityQueue is to remove the element that you changed, and then re-insert it.

Related

best way to Iterate over a collection and array consecutively

Its a very trivial question and related to coding Style and I am just asking to make my coding style more readable
Suppose I have a Collection like linkedList and an Array and I need to iterate over both simultaneously.
currently the best way I know is to get a iterator over list and define a index variable outside the iterator loop and increment the index variable simultaneously to access both next elements {list and array}. Please refer the example below
LinkedList<Integer> list = new LinkedList<Integer>();
Integer[] arr = new Array[25];
// lets suppose both have 25 elements.
// My Iteration method will be
int index =0;
for (Integer val : list) {
System.out.println(val);
System.out.println(arr[index++]);
}
so is it the only way or is there any other way I can perform this iteration in more readable and more relatable manner, where I don't have to take index variable separately.
I know it can be possible that array might have less or more elements than collection but I am only talking about the cases where they have equal and we need to iterate over Both of them.
PS : anybody can write a code that a computer can understand, actual challenge is to write code which humans can understand easily.
What you have is essentially fine: it's simple, and simple can be sufficient to make code readable.
The only thing I would caution about is the side effect of index++ inside arr[index++]: if, say, you want to use the same value multiple times in the loop body, you couldn't simply copy+paste.
Consider pulling out a variable as the first thing in the loop to store the "current" array element (which is essentially what the enhanced for loop does for the list element).
for (Integer val : list) {
Integer fromArr = arr[index++];
// ...
}
Just to point out an alternative without having a separate variable for the index, you can use ListIterator, which provides you with the index of the element.
// Assuming list and are have same number of elements.
for (ListIterator<Integer> it = list.listIterator();
it.hasNext();) {
// The ordering of these statements is important, because next() changes nextIndex().
Integer fromArr = arr[it.nextIndex()];
Integer val = it.next();
// ...
}
ListIterator is not an especially widely-used class, though; its use may in and of itself be confusing.
One of the downsides of the ListIterator approach is that you have to use the it correctly: you shouldn't touch it inside the loop (after getting the values), you have to put the statements in the right order, etc.
Another approach would be to create a library method analogous to Python's enumerate:
static <T> Iterable<Map.Entry<Integer, T>> enumerate(Iterable<? extends T> iterable) {
return () -> new Iterator<T>() {
int index = 0;
Iterator<? extends T> delegate = iterable.iterator();
#Override public boolean hasNext() { return delegate.hasNext(); }
#Override public Map.Entry<Integer, T> next() {
return new AbstractMap.SimpleEntry<>(index++, delegate.next());
}
};
}
This returns an iterable of map entries, where the key is the index and the value is the corresponding value.
You could then use this in an enhanced for loop:
for (Map.Entry<Integer, Integer> entry : enumerate(list)) {
Integer fromList = entry.getValue();
Integer fromArr = arr[entry.getKey()];
}
One option is to have 2 iterators, but I don't think it is any clearer:
for (Iterator<Integer> i1 = list.iterator(), i2 = Arrays.asList(arr).iterator();
i1.hasNext() && i2.hasNext();) {
System.out.println(i1.next());
System.out.println(i2.next());
}
But it is more robust in that it finishes at the shorter of the 2 collections.
I tried to simplify and handle size wise collections where both need not be of the same size. I believe this would work even if the sizes are not same and just one loop would suffice. Code snippet below:
LinkedList<Integer> list = new LinkedList<Integer>();
Integer[] arr = new Array[25];
int maxLength= Math.max(list.size(),arr.size());
//Looping over the lengthy collection( could be Linkedlist or arraylist)
for(int i=0;i<maxLength;i++){
if(list.size()>i)
System.out.println(list[i]);
if(arr.size()>i)
System.out.println(arr[i]);
}
Hope this helps! Thanks

Create a sub-list according to criteria and Perform operations

I have sorted List<Pair<Integer, Integer>> and I want to create a subList for all the Pairs which having a key less than one arbitrary value k.
I want to create a subList that follows above condition and sort it.
I did something like this -
//to get the max index of the List
public static int getIndex(List<Pair<Integer,Integer>> list,int key)
{
int count=0;
for(Pair<Integer,Integer> p: list)
{
if(p.getKey()>key)
break;
count++;
}
return count;
}
Now, Sorting subList as per this criteria
int count = getIndex(current.getValue(),list);
Collections.sort(list.subList(0, count),Comparator.<Pair<Integer,Integer>>comparingInt(Pair::getValue));
Is there any elegent way to do achieve this ? I mean java 8 way.
Stream API came into my mind. But after performing operations it doesn't manipulate the underlined collection.
Something like the following.
List<Pair<Integer,Integer>> subList =
list.stream()
.filter(p->p.getKey() < key)
.collect(Collectors.toList());
This works regardless of the ordering of the pairs in the list. It constructs the new list as each pair passes thru the filter.

How to get nth element of a Set

More specifically: how to get the nth element of a LinkedHashSet (which has a predictable iteration order)? I want to retrieve the nth element inserted into this Set (which wasn't already present).
Is it better to use a List:
List<T> list = new ArrayList<T>(mySet);
T value = list.get(x); // x < mySet.size()
or the toArray(T [] a) method:
T [] array = mySet.toArray(new T[mySet.size()]);
T value = array[y]; // y < mySet.size()
Other than the (likely slight) performance differences, anything to watch out for? Any clear winner?
Edit 1
NB: It doesn't matter why I want the last-inserted element, all that matters is that I want it. LinkedHashSet was specifically chosen because it "defines the iteration ordering, which is the order in which elements were inserted into the set (insertion-order). Note that insertion order is not affected if an element is re-inserted into the set."
Edit 2
This question seems to have devolved into a discussion of whether any Set implementation can ever preserve original insertion order. So I put up some simple test code at http://pastebin.com/KZJ3ETx9 to show that yes, LinkedHashSet does indeed preserve insertion order (the same as its iteration order) as its Javadoc claims.
Edit 3
Modified the description of the problem so that everybody isn't too focused on retrieving the last element of the Set (I originally thought that the title of the question would be enough of a hint — obviously I was wrong).
This method is based on the updated requirement to return the nth element, rather than just the last element. If the source is e.g. a Set with identifier mySet, the last element can be selected by nthElement(mySet, mySet.size()-1).
If n is small compared to the size of the Set, this method may be faster than e.g. converting to an ArrayList.
/**
* Return an element selected by position in iteration order.
* #param data The source from which an element is to be selected
* #param n The index of the required element. If it is not in the
* range of elements of the iterable, the method returns null.
* #return The selected element.
*/
public static final <T> T nthElement(Iterable<T> data, int n){
int index = 0;
for(T element : data){
if(index == n){
return element;
}
index++;
}
return null;
}
I'd use the iterator of the LinkedHashSet if you want to retrieve the last element:
Iterator<T> it = linkedHashSet.iterator();
T value = null;
while (it.hasNext()) {
value = it.next();
}
After the loop execution value will be referring to the last element.
So I decided to go with a slight variation of the answer by #Juvanis.
To get at the nth element in a LinkedHashSet:
Iterator<T> itr = mySet.iterator();
int nth = y;
T value = null;
for(int i = 0; itr.hasNext(); i++) {
value = itr.next();
if (i == nth) {
break;
}
}
Version 2 of the code:
public class SetUtil {
#Nullable
public static <T> T nthElement(Set<T> set, int n) {
if (null != set && n >= 0 && n < set.size()) {
int count = 0;
for (T element : set) {
if (n == count)
return element;
count++;
}
}
return null;
}
}
NB: with some slight modifications the method above can be used for all Iterables<T>.
This avoids the overhead of ensuring that a Set and a List stay in sync, and also avoids having to create a new List every time (which will be more time-consuming than any amount of algorithmic complexity).
Obviously I am using a Set to ensure uniqueness and I'd rather avoid a lengthy explanation as to why I need indexed access.
You can go with below solution,
here i have added object of ModelClass in HashSet.
ModelClass m1 = null;
int nth=scanner.nextInt();
for(int index=0;index<hashset1.size();index++){
m1 = (ModelClass) itr.next();
if(nth == index) {
System.out.println(m1);
break;
}
}
Set is unordered so the information on the last element inserted is lost. You cannot as such get the last element inserted. So don't use Set in the first place, or, if you really want to keep track of the last element, create a class containing that like this
class mySetAndLast extends Set{
T last;
Set<T> mySet;
}
now the question is what is the 'last element inserted'. Imagine your set was empty
-> insert x -> ok, x is the last inserted
-> insert y (y!=x) -> ok: y is the last inserted
-> insert x -> ?
is now x or y the last inserted?
x does not get inserted because y was the last element inserted and x already is an element of the set, on the other hand x from the user's point of view was the last inserted..
For your own, internal purpose, you could "hack" your own Set from any List implementation:
public class ListSet<E> extends ArrayList<E> implements Set<E> {
#Override
public boolean add(E item) {
return contains(item) ? false : super.add(item);
}
// ... and same for add(int, E), addAll(...), etc.
}
That example is slow (O(n) for an add) but, as you are the one implementing it, you can go back to it with smarter code for contains() based on your specifications.

Poset iteration order / custom iterator implementation for a partially ordered set

I am creating a partially ordered set as an abstract data type in java, and I have to make an iterator version of the set of numbers, and an iterator for the relations. Now for the elements, I've used HashSet of integer, and for the relations, I've used an ArrayList of pairs (pairs is a class I created that takes 2 ints as parameter which basically is like (x, y)). I need to make 2 iterators, one for s and one for r, but they have to follow a certain ordering,
1. if (x, y) belong to R, then the iterator of s should return x before it returns y
2. if (x, y) and (y, z) belong to R, then iterator of r should return (x, y) before it returns (y, z)
I made a helper method that check first for to check if the element n in the set is the first element in a pair then it returns it, but I cant seem to check if it is second element, how can I check for the first element if it is returned or not?
Here is my code:
private class IntGenerator implements Iterator {
private Iterator<Integer> i;
public IntGenerator () {
i = S.iterator();
}
public boolean hasNext() {
return i.hasNext();
}
public Object next() {
int n = i.next();
for (Pair p : R) {
if (isInFirstElmPair(p, n)) return n;
else (isInSecondElmPair(p, n)) {
// should check for the first element
// if it was returned or not
}
}
}
public void remove() { throw new UnsupportedOperationException(); }
}
I would really appreciate any kind of help, or hint in this code.
Thanks
EDIT:
Okay, I've wrote the code to it after adding a new set which will hold the returned elements, and this is what I wrote:
Set<Integer> returnedNumbers = new HashSet<Integer> ();
public Object next() {
int n = i.next();
for (Pair p : R) {
if (isInSecondElmPair(p, n)) {
if (returnedNumbers.contains(p.getFirstElm())) {
returnedNumbers.add(n);
return n;
}else{
returnedNumbers.add(p.getFirstElm());
return p.getFirstElm();
}
}else{
returnedNumbers.add(n);
return n;
}
}
}
Is this code correct? Also, eclipse seems to give me an error telling me I need to return a value outside the loop, but I already returned inside for every case why does it need more?
Appreciate the help
Well, to check if a value was previously returned, you of course need to keep track of all values that were returned previously.
So in your iterator, you could define
Set<Integer> previouslyReturned = new HashSet<Integer>();
and then, before returning it in your for loop, add it there:
if (isInFirstElmPair(p, n)) {
previouslyReturned.add(n);
return n;
}
else (isInSecondElmPair(p, n)) {
if (previouslyReturned.contains(n) {
// do one thing
} else {
// do another thing
}
}
This way, however, you are constructing a set of s in the order in which it shall be returned inside the iterator. It would make sense to create this once (consider a LinkedHashSet), keep it somewhere else and iterate over it.
Generally I am not sure that this approach will lead to what you want. Do you know anything about theorder of elements in S and R? If the iteration order is arbitrary (i.e. because relations were added in unpredictable order) then the iterator will first return the first half of the first relation pair, even if that element is in the second half of another pair. Do you have to use an element HashSet and a relation List?

Building a custom iterator

I am making this class which is a custom Map based off a hash map. I have an add method where if you add an object the object will be the key, and its value will be 1 if the object is not currently in the list. However if you add object that is currently in the list its value will be bumped up by 1. So if I added 10 strings which were all the same, the key would be that string and the value will be 10. I understand in practice when I iterate through the map, there is actually only one object to iterate, however, I am trying to create a inner class that will define an iterator that will iterate the same object however many times its value is. I can do this by simply using for loops to construct an appropriate ArrayList and just create an iterator for that, but that is too inefficient. Is there an easy or more efficient way of doing this?
You can do it with two variables:
private T nextObj = null;
private int times = 0;
T next(){
if(times==0){
// get the next object and set the times variable to it's value in the hashmap
}
times--;
return nextObj;
}
You could use nCopies from the collections API. This will create a list with only one reference so it will be efficient. Then just return that Lists iterator. No need to create an inner class.
Assuming your Map<String, Integer> instance variable is called map, you could do the following:
Iterator<String> customIteratorForKey(String key) {
return Collections.nCopies(map.get(key), key).iterator();
}
It sounds like you're implementing a multiset or bag: a set that counts each unique element. Since this is a school project, I'll give some pointers on how to do it instead of providing code. Try your luck with it and refine your question if you get stuck.
When I create a new collection type that uses another collection behind it, I typically do the same thing when building the iterator.
Bag.Iterator's constructor would initialize itself with an iterator from the Map.
As dtech showed above, the iterator needs to track the current object it is counting and the number of times it should return it.
next() needs to get the next object at the start and once the current object runs out of counts.
hasNext() must do the same thing without actually decreasing the count or grabbing the next object.
I finally figured it out. Here is my solution. Thanks to everyone who responded and gave me pointers.
private int times = 0;
private boolean flag = true;
Iterator<Entry<T, Integer>> it = Bag.entrySet().iterator();
private Entry<T, Integer> t = it.next();
private int value = t.getValue();
private T nextObj = t.getKey();
public boolean hasNext() {
if (times > 0) {
return true;
}
return it.hasNext();
}
public T next() {
if (this.hasNext() == false) {
throw new NoSuchElementException();
}
if (times == 0 && flag == true) {
times = value;
flag = false;
}
if (times == 0 && flag == false) {
t = it.next();
value = t.getValue();
nextObj = t.getKey();
times = value;
}
times--;
return nextObj;
}

Categories

Resources