Java Priority Queue with ArrayLists and Pairs - java

I'm looking for simple way to build a Priority Queue in Java. I've built an ArrayList<Pair>, and each Pair instance contains an X and Y values.
class Pair {
private final Float xVal;
private final Float yVal;
public Pair(Float aXVal, Float aYVal) {
xVal = aXVal;
yVal = aYVal;
}
public float getX() {
return xVal;
}
public float getY() {
return yVal;
}
}
My ArrayList looks like:
ArrayList<Pair> listOfPoints;
Using the ArrayList listOfPoints, I wanted to build two priority queues:
One that is sorted on the x Values from low to high.
One that is sorted on the y Values form low to high.
I was looking for a simple way to do this using Lambda expressions.
I did look at this question on Stack Overflow, and I found this code:
PriorityQueue<String> pq=
new PriorityQueue<String>(5,(a,b) -> a.length() - b.length());
I think this is close to what I want.
I was trying to implement the following:
PriorityQueue<Pair> xSorted = new PriorityQueue<Pair>(numOfPoints, (x1,x2) -> Need Help Here);
How do I access Pair in order to have it compare x1 and x2?
Note, that nummberOfPoints I was setting to the length of ArrayList<Pair> listOfPoints.

For the natural (ascending) order based on xVal:
PriorityQueue<Pair> pq= new PriorityQueue<>(Comparator.comparingDouble(Pair::getX));
For the reversed (descending) order based on xVal:
PriorityQueue<Pair> pq= new PriorityQueue<>(Comparator.comparingDouble(Pair::getX).reversed());
You can use the same approach for yVal or any other comparable field, by using Comparator API.

You can also use lambda like this if you don't want Pair class to implement Comparator interface
PriorityQueue<Pair> queue = new PriorityQueue<>(5, (p1, p2) -> Float.compare(p1.getX(), p2.getX()));
For reverse order:
PriorityQueue<Pair> queue = new PriorityQueue<>(5, (p1, p2) -> Float.compare(p2.getX(), p1.getX()));
If you prefer your comparison logic in a static factory method or utility function, you can use something like this:
PriorityQueue<Pair> queue = new PriorityQueue<>(NodeUtil::customCompare);
public static int customCompare(Pair p1, Pair p2) {
return Float.compare(p1.getX(), p2.getX());
}

Related

How to sort a Map by Key and Value, whereas the Val is a Map/List itself

I am having a hard time understanding the right syntax to sort Maps which values aren't simply one type, but can be nested again.
I'll try to come up with a fitting example here:
Let's make a random class for that first:
class NestedFoo{
int valA;
int valB;
String textA;
public NestedFoo(int a, int b, String t){
this.valA = a;
this.valB = b;
this.textA = t;
}
}
Alright, that is our class.
Here comes the list:
HashMap<Integer, ArrayList<NestedFoo>> sortmePlz = new HashMap<>();
Let's create 3 entries to start with, that should show sorting works already.
ArrayList<NestedFoo> l1 = new ArrayList<>();
n1 = new NestedFoo(3,2,"a");
n2 = new NestedFoo(2,2,"a");
n3 = new NestedFoo(1,4,"c");
l1.add(n1);
l1.add(n2);
l1.add(n3);
ArrayList<NestedFoo> l2 = new ArrayList<>();
n1 = new NestedFoo(3,2,"a");
n2 = new NestedFoo(2,2,"a");
n3 = new NestedFoo(2,2,"b");
n4 = new NestedFoo(1,4,"c");
l2.add(n1);
l2.add(n2);
l2.add(n3);
l2.add(n4);
ArrayList<NestedFoo> l3 = new ArrayList<>();
n1 = new NestedFoo(3,2,"a");
n2 = new NestedFoo(2,3,"b");
n3 = new NestedFoo(2,2,"b");
n4 = new NestedFoo(5,4,"c");
l3.add(n1);
l3.add(n2);
l3.add(n3);
l3.add(n4);
Sweet, now put them in our Map.
sortmePlz.put(5,l1);
sortmePlz.put(2,l2);
sortmePlz.put(1,l3);
What I want now, is to sort the Entire Map first by its Keys, so the order should be l3 l2 l1.
Then, I want the lists inside each key to be sorted by the following Order:
intA,intB,text (all ascending)
I have no idea how to do this. Especially not since Java 8 with all those lambdas, I tried to read on the subject but feel overwhelmed by the code there.
Thanks in advance!
I hope the code has no syntatical errors, I made it up on the go
You can use TreeSet instead of regular HashMap and your values will be automatically sorted by key:
Map<Integer, ArrayList<NestedFoo>> sortmePlz = new TreeMap<>();
Second step I'm a little confused.
to be sorted by the following Order: intA,intB,text (all ascending)
I suppose you want to sort the list by comparing first the intA values, then if they are equal compare by intB and so on. If I understand you correctly you can use Comparator with comparing and thenComparing.
sortmePlz.values().forEach(list -> list
.sort(Comparator.comparing(NestedFoo::getValA)
.thenComparing(NestedFoo::getValB)
.thenComparing(NestedFoo::getTextA)));
I'm sure there are way of doing it with lambda but it is not actually required. See answer from Schidu Luca for a lambda like solution.
Keep reading if you want an 'old school solution'.
You cannot sort a map. It does not make sense because there is no notion of order in a map. Now, there are some map objects that store the key in a sorted way (like the TreeMap).
You can order a list. In your case, makes the class NestedFoo comparable (https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html). Then you can invoke the method Collections.sort (https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#sort-java.util.List-) on your lists.
Use TreeMap instead of HashMap, it solves the 1st problem: ordering entries by key.
After getting the needed list from the Map, you can sort the ArrayList by valA, valB, text:
l1.sort(
Comparator.comparing(NestedFoo::getValA).thenComparing(NestedFoo::getValB).thenComparing(NestedFoo::getTextA)
);
And change your NestedFoo class definition like this:
class NestedFoo {
int valA;
int valB;
String textA;
public NestedFoo(int a, int b, String t) {
this.valA = a;
this.valB = b;
this.textA = t;
}
public int getValA() {
return valA;
}
public void setValA(int valA) {
this.valA = valA;
}
public int getValB() {
return valB;
}
public void setValB(int valB) {
this.valB = valB;
}
public String getTextA() {
return textA;
}
public void setTextA(String textA) {
this.textA = textA;
}
}
When using treemap for sorting keep in mind that treemap uses compareTo instead of equals for sorting and to find duplicity. compareTo should be incosistent with equals and hashcode when implemented for any object which will be used as key. You can look for a detailed example on this link https://codingninjaonline.com/2017/09/29/unexpected-results-for-treemap-with-inconsistent-compareto-and-equals/

Java Lambda Multiple operations on a single stream

Scenario: I have a object with 2 functions -->
<Integer> getA(); <Integer> getB();
I have a list of objects, say List<MyObject> myObject.
Objective Iterate over the List and get sum of A and B's in the List of object.
My Solution
myObject.stream().map(a -> a.getA()).collect(Collectors.summingDouble());
myObject.stream().map(a -> a.getB()).collect(Collectors.summingDouble());
The Question: How can I do both of these at the same time? This way I will not have to iterate twice over the original list.
#Edit: I was doing this because some of the filters that I used were of O(n^3). Kind of really bad to do those twice.
Benchmark : It really matters if it is T or 2T when the program runs for half hour on an i5. This was on much lesser data and if I run on a cluster, my data would be larger too.
It does matter if you can do these in one line!.
You need to write another class to store the total values like this:
public class Total {
private int totalA = 0;
private int totalB = 0;
public void addA(int a) {
totalA += a;
}
public void addB(int b) {
totalB += b;
}
public int getTotalA() {
return totalA;
}
public int getTotalB() {
return totalB;
}
}
And then collect the values using
Total total = objects.stream()
.map(o -> (A) o)
.collect(Total::new,
(t, a) -> {
t.addA(a.getA());
t.addB(a.getB());
},
(t1, t2) -> { });
//check total.getTotalA() and total.getTotalB()
You can also use AbstractMap.SimpleEntry<Integer, Integer> to replace Total to avoid writing a new class, but it's still kind of weird because A/B are not in a key-value relationship.
The most optimal probably still would be a for loop. Though the stream alternative has parallelism as option, and is likely to become as efficient soon.
Combining two loops to one is not necessarily faster.
One improvement would be to use int instead of Integer.
List<String> list = Arrays.asList("tom","terry","john","kevin","steve");
int n = list.stream().collect(Collectors.summingInt(String::length));
int h = list.stream().collect(Collectors.summingInt(String::hashCode));
I favour this solution.
If one would make one loop, there are two alternatives:
putting both ints in their own class. You might abuse java.awt.Point class with int x and int y.
putting both ints in a long. When no overflow, then one can even sum in the loop on the long.
The latter:
List<String> list = Arrays.asList("tom","terry","john","kevin","steve");
long nh = list.stream()
.collect(Collectors.summingLong((s) -> (s.hashCode() << 32) | s.length()));
int n = (int) nh;
int h = (int) (nh >> 32L);

How to sort object using a multi map?

Hi I'm trying to sort an object based on a value of that object. Originally I used TreeMap which did the sorting but there were some non-unique keys which were removed so that didn't work. I googled around and came across Guava MultiMap. But how do I actually use this to sort the values?
Basically I'm trying to sort budget information based on the diffYTD_percentage value. Thanks!
Multimap<Double, BudgetInformation> multiMap = ArrayListMultimap.create();
for (Budget budget : budgets) {
BudgetInformation budgetInfo = getBudget(budget.getId());
double actualToDate = budgetInfo.getActualToDate();
double budgetToDate = budgetInfo.getTotalBudgetToDate();
double diffYTD_value = budgetToDate - actualToDate;
double diffYTD_percentage_value = 0.0;
if (budgetToDate != 0.0) {
double fraction = actualToDate / budgetToDate;
fraction = fraction - 1;
diffYTD_percentage_value = fraction * 100;
}
multiMap.put(diffYTD_percentage_value, budgetInfo);
}
Iterator<BudgetInformation> budgetIterator = multiMap.values().iterator();
Using Tree in order to sort collection is wrong approach. In Java there are dedicated utility methods to sort list, Collections.sort(List<T extends Comparable<? super T>> list) and Collections.sort(List<T> list, Comparator<? super T> c). The first is used to sort list where elements have natural ordering (basically implement Comparable interface), the later is used in cases like your own, when you need to sort elements using custom ordering.
So, basically what you need to do is to create Comparator that will compare two BusinessInfo instances based on diffYTD_percentage_value and call Collections.sort with this comparator.
Comparator<BudgetInformation> budgetInfoCmp = new Comparator<BudgetInformation>() {
private double getDiffYTDPercentage(BudgetInformation budgetInfo) {
double actualToDate = budgetInfo.getActualToDate();
double budgetToDate = budgetInfo.getTotalBudgetToDate();
double diffYTDValue = budgetToDate - actualToDate;
double diffYTDPercentageValue = 0.0;
if (budgetToDate != 0.0) {
double fraction = actualToDate / budgetToDate;
fraction = fraction - 1;
diffYTDPercentageValue = fraction * 100;
}
return diffYTDPercentageValue;
}
#Override
public int compare(BudgetInformation o1, BudgetInformation o2) {
return Double.compare(getDiffYTDPercentage(o1), getDiffYTDPercentage(o2));
}
};
List<BudgetInformation> budgetInformationsToSort = getBudgetInformations();
Collections.sort(budgetInformationsToSort, budgetInfoCmp);
Also try to avoid using underscore in variable naming, as under Java naming convention variable names should be in camel case.
How about using TreeMultiMap? It doesnt support duplicate key-value pair. But duplicate keys are fine.

Ordering the items in the array

Hi am trying to draw polygons on the map depending on the shortest distance.
i have created the array list called distancearray.
but i want to create a new array list called shortdistance, this array list must have the same values in the distancearray but it must be shorted in assending order depending on the distance.
can any one help me to create this shortdistance array. Thank you.
String array[][]=dbhand.collecting(getIntent().getExtras().getString("temple_type"), Integer.parseInt(getIntent().getExtras().getString("notemples")));
for(int i=0;i<array.length;i++){
displaymarkers(Double.parseDouble(array[i][0]), Double.parseDouble(array[i][1]), array[i][2]);
}
for(int i=0;i<array.length;i++){
double Distance = calculate_distance(SEATTLE_LAT, SEATTLE_LNG, Double.parseDouble(array[i][0]), Double.parseDouble(array[i][1]));
double[][] distancearray = new double[array.length][3];
distancearray[i][0]=Double.parseDouble(array[i][0]);
distancearray[i][1]=Double.parseDouble(array[i][1]);
distancearray[i][2]=Distance;
}
double [][] shortdistance = new double [array.length][3];
Draw Polygon Function
private void drawpolygon(String array[][]) {
int lengh = array.length;
if(lengh==2){
mMap.addPolygon(new PolygonOptions()
//.add(new LatLng(9.662502, 80.010239), new LatLng(9.670931, 80.013201), new LatLng(9.663216, 80.01333))
.add(new LatLng(9.6632139, 80.0133258))
.add(new LatLng(Double.parseDouble(array[0][0]), Double.parseDouble(array[0][1])))
.add(new LatLng(Double.parseDouble(array[1][0]), Double.parseDouble(array[1][1])))
.fillColor(Color.GRAY));
}
Just call Arrays.sort() against your array and specify a comparator that looks at the distance.
You are going to have difficulty sorting your arrays as-is because you currently store your data in parallel arrays:
distancearray[i][0]=Double.parseDouble(array[i][0]);
distancearray[i][1]=Double.parseDouble(array[i][2]);
distancearray[i][3]=Distance;
You can sort distancearray[n] but that will give you nonsense results. Instead what you should do is create a small class that implements Comparable (comparing based on distance) that holds your three values, then work with an array of those classes:
class DistanceInfo implements Comparable<DistanceInfo> {
public double a;
public double b;
public double distance;
public DistanceInfo (double a, double b, double distance) {
this.a = a;
this.b = b;
this.distance = distance;
}
#Override public int compareTo (DistanceInfo d) {
return Double.compare(distance, d.distance);
}
}
// then:
DistanceInfo[] distancearray = new DistanceInfo[array.length];
// and you can load it using the constructor:
for (int i = 0; i < array.length) {
double a = Double.parseDouble(array[i][0]);
double b = Double.parseDouble(array[i][1]);
distancearray[i] = new DistanceInfo(a, b, Distance);
}
(The fields can be made final if you wish to specify that they cannot be modified after construction.)
Now, Arrays.sort() will sort distancearray based on distance:
Arrays.sort(distancearray, null);
You could also use an ArrayList<DistanceInfo> instead, the idea is the same except you sort with Collections.sort().
In general, for this reason (among others) it is usually better to use a class to store all information about an object as opposed to parallel arrays.
As an aside, you may want to consider using this class for array as well, it will simplify your code a bit (you can modify displaymarkers to take a DistanceInfo, and you can also avoid parsing the same double more than once).

Using selection sort in java to sort floats

Hey, I need to sort an array list of class house by a float field in a certain range. This is my code for the selection sort:
Basically sortPrice copies the stuff in this list into a new one selecting only the values in that range, then it does a selection sort in that array list. The arraylist (x) in sortPrice is unsorted an needs to be copied because what x references cannot be altered.
public ArrayList<House> sortPrice(ArrayList<House> x,float y, float z){
ArrayList<House> xcopy = new ArrayList<House>();
for(int i = 0; i<x.size(); i++){
if(x.get(i).myPriceIsLessThanOrEqualTo(z) && x.get(i).myPriceIsGreaterThanOrEqualTo(y)){
xcopy.add(x.get(i));
}
}
ArrayList<House> price= new ArrayList<House>();
while(xcopy.size()>0){
House min = xcopy.get(0);
for(int i = 1; i < xcopy.size();i++){
House current = xcopy.get(i);
if (current.myPriceIsGreaterThanOrEqualTo(min.getPrice())){
min = current;
}
}
price.add(min);
xcopy.remove(min);
}
return price;
}
Here is what the house class looks like:
public class House {
private int numBedRs;
private int sqft;
private float numBathRs;
private float price;
private static int idNumOfMostRecentHouse = 0;
private int id;
public House(int bed,int ft, float bath, float price){
sqft = ft;
numBathRs = bath;
numBedRs = bed;
this.price = price;
idNumOfMostRecentHouse++;
id = idNumOfMostRecentHouse;
}
public boolean myPriceIsLessThanOrEqualTo(float y){
if(Math.abs(price - y)<0.000001){
return true;
}
return false;
}
public boolean myPriceIsGreaterThanOrEqualTo(float b){
if(Math.abs(b-price)>0.0000001){
return true;
}
return false;
}
When i call looking for houses in range 260000.50 to 300000 I only get houses that are at the top of the range even though I have a lower value at 270000. Can someone help?
You should use rounded double type.
DecimalFormat p= new DecimalFormat( "#0.00" );
double price = 123.00001;
price = new Double(p.format(price)).doubleValue();
Your method name indicates it sorts the data, the method also filters. You need to change the name. Actually there are a number of variables in this code which need their names change to better reflect what they contain.
You need to replace the for loops with for-each loops. That will simply and make the code clearer. You would also no longer need the while() statement.
I would also refactor the mypriceis... methods into a single ispriceinrange method.
Alternatively I'd look at the comparator interface and look at introducing it as a way to sort you data without having to hand code a loop.
Just took a second look. You do actually sort in the second loop, but that some ugly code and probably won't perform well to boot. Definitely go look at comparator and Collections.sort() methods. Save yourself a world of pain.
The best data structure for this problem would be a NavigableMap<Float,List<House>> (such as a TreeMap), which supports a subMap operation:
SortedMap<K,V> subMap(K fromKey, K toKey) : Returns a view of the portion of this map whose keys range from fromKey, inclusive, to toKey, exclusive.
There is also an overload that allows you to set inclusive bounds.
Here's a demonstration:
NavigableMap<Integer,String> nmap = new TreeMap<Integer,String>();
nmap.put(5, "Five");
nmap.put(1, "One");
nmap.put(7, "Seven");
nmap.put(3, "Three");
System.out.println(nmap.subMap(2, 6));
// prints {3=Three, 5=Five}
For your case, you'd want to either make House implementsComparable<House>, or define your own custom Comparator<House>. You'd then let TreeMap do the sorting for you, and don't have to deal with selection sort (which, at O(N^2), is far from optimal).
If you're stuck with the specification that you're given, then I'd suggest breaking apart the logic into helper methods like these:
List<House> filterInRange(List<House> houses, float low, float high) {
List<House> ret = new ArrayList<House>();
for (House h : houses) {
if (isInRange(h.getPrice(), low, high)) {
ret.add(h);
}
}
return ret;
}
static boolean isInRange(float v, float low, float high) { ...DIY... }
void selectionSort(List<House> houses) { ...Wikipedia... }
Then to get a sorted List<House> in a specified price range, invoke filterInRange and then selectionSort the returned list.
See also
Java language guide/for-each

Categories