Help comparing float member variables using Comparators - java

I am able to compare Strings fine, but would like to know how I can rank floating point numbers?
getChange() returns a String. I want to be able to sort descending. How can I do this?
UPDATE:
package org.stocktwits.helper;
import java.util.Comparator;
import org.stocktwits.model.Quote;
public class ChangeComparator implements Comparator<Quote>
{
public int compare(Quote o1, Quote o2) {
float change1 = Float.valueOf(o1.getChange());
float change2 = Float.valueOf(o2.getChange());
if (change1 < change2) return -1;
if (change1 == change2) return 0; // Fails on NaN however, not sure what you want
if (change2 > change2) return 1;
}
}
I am getting the compile time error:
This method must return a result of type int ChangeComparator.java

How about this:
public class ChangeComparator implements Comparator<Quote>
{
public int compare(Quote o1, Quote o2) {
Float change1 = Float.valueOf(o1.getChange());
Float change2 = Float.valueOf(o2.getChange());
return change1.compareTo(change2);
}
}
Note that Java 1.4 introduced Float#compare(float, float) (and an equivalent in Double), which can be pretty much used directly:
public class ChangeComparator implements Comparator<Quote>
{
public int compare(Quote o1, Quote o2) {
return Float.compare(o1.getChange(), o2.getChange());
}
}
(After editing, I notice that #BorislavGizdov has mentioned this in his answer already.)
Also worth noting that Java 8 Comparator#comparing(...) and Comparator#comparingDouble(...) provide a straightforward way of constructing these comparators directly.
Comparator<Quote> changeComparator = Comparator.comparing(Quote::getChange);
Will compare using boxed Float values.
Comparator<Quote> changeComparator = Comparator.comparingDouble(Quote::getChange);
Will compare using float values promoted to double values.
Given that there is no Comparator#comparingFloat(...), my preference would be to use the comparingDouble(...) method, as this only involves primitive type conversion, rather than boxing.

Read the javadoc of Comparator#compare() method.
Compares its two arguments for order. Returns a negative integer, zero or a positive integer as the first argument is less than, equal to or greater than the second.
So, basically:
float change1 = o1.getChange();
float change2 = o2.getChange();
if (change1 < change2) return -1;
if (change1 > change2) return 1;
return 0;
Or if you like conditional operators:
return o1.getChange() < o2.getChange() ? -1
: o1.getChange() > o2.getChange() ? 1
: 0;
You however need to take account with Float.NaN. I am not sure how you'd like to have them ordered. First? Last? Equally?

You can use Float.compare(float f1, float f2):
public static int compare(float f1, float f2)
Compares the two specified float values. Returns the value 0 if f1 is numerically equal to f2; a value less than 0 if f1 is numerically less than f2; and a value greater than 0 if f1 is numerically greater than f2.

import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
Scanner input = new Scanner(System.in);
int tc = input.nextInt();
int alpha = 0;
while (tc-- > 0) {
int ttc = input.nextInt();
int sort = input.nextInt();
input.nextLine();
Vector<student> v = new Vector<>();
alpha++;
while (ttc-- > 0) {
String name = input.next();
int weit = input.nextInt();
int age = input.nextInt();
float hight = input.nextFloat();
v.add(new student(name, weit, age, hight));
}
Collections.sort(v);
int count = 0;
System.out.println("CENARIO {" + alpha + "}");
for (student s : v) {
System.out.print((count + 1) + " - ");
System.out.println(s.name);
count++;
if (count == sort) {
break;
}
}
}
}
private static class student implements Comparable<student> {
String name;
int weit;
int age;
float hight;
public student(String name, int weit, int age, float hight) {
this.name = name;
this.weit = weit;
this.age = age;
this.hight = hight;
}
#Override
public int compareTo(student t) {
if (this.weit - t.weit != 0) {
return t.weit - this.weit;
}
if (this.age - t.age != 0) {
return this.age - t.age;
}
if (this.hight - t.hight != 0) {
return Float.compare(this.hight, t.hight);
}
return this.name.compareTo(t.name);
}
}
}

Related

OOP in Java: problem with constructor and methods

I am new to Java and I am trying to write a class with constructors and methods that adds and divides two numbers, and also compares if one object is larger or equal than the other. But I am getting an error: The method plus(int) in the type Compare is not applicable for the arguments (Compare). what's wrong?
Here's the code:
public class Compare {
// fields
private int number;
private int plus;
private double div;
// constructor
public Compare (int n) {
number = n;
}
public int plus (int x) {
return this.number + x;
}
public int div (int x) {
return this.number / x;
}
public boolean isLargerThan (int x) {
return this.number > x;
}
public boolean isEqualTo (int x) {
return this.number == x;
}
public static void main(String[] args) {
Compare n1 = new Compare(9);
Compare n2 = new Compare(4);
Compare sum = n1.plus(n2);
Compare div = n1.div(n2);
boolean check1 = sum.isLargerThan(n1);
boolean check2 = div.isLargerThan(n2);
boolean check3 = div.isEqualto(sum);
}
}
The requirement is to create sum and div objects using Compare constructor that will be equal to n1 plus n2, with plus method or division as applicable.
It may be that here you want a new Compare, containing the sum.
public Compare plus (int x) {
return new Compare(number + x);
}
public Compare plus (Compare x) {
return new Compare(number + x.number);
}
This also is implied by expecting a Compare object, not an int as shown.
With that Compare would become immutable, which is very good, as you then can share objects in different variables without problems (changing one variable's value changing other variables' values).
#Override
public String toString() {
return Integer.toString(number);
}
public int intValue() {
return number;
}
The issue here is for the "plus", "div", "isLargerThan" and "isEqualTo" methods in "Compare" class the argument/return type is of type "int". But in "main" function you are passing the object and expecting object of type "Compare".
To fix it either change the argument/return type to "Compare" for those methods in "Compare" class or pass the "int" value as parameter and get "int" value in "main" function.
The plus and div methods take an int and return an int and you are trying to receive their output in a Compare object. Also, isLargerThan takes an int and not a Compare.
Problem is here :
Compare sum = n1.plus(n2);
Compare div = n1.div(n2);
methods : plus and div return int value not an objet of Class Compare.
public int plus (int x) {
return this.number + x;
}
public int div (int x) {
return this.number / x;
}
Add getter method in Compare Class.
public int getNumber(){
return number;
}
Use below code and try to run:
public static void main(String[] args) {
Compare sum = new Compare(9);
Compare divObj = new Compare(4);
sum.plus(n2);
divObj.div(n2);
boolean check1 = sum.isLargerThan(sum.getNumber());
boolean check2 = divObj.isLargerThan(divObj.getNumber());
boolean check3 = divObj.isEqualto(sum.getNiumber());
}

How Comparator internally works with ArrayList?(How to trace comparators working w.r.t Arraylist)

can anyone please explain me how comaprator internally works with ArrayList?
My code is working but I am not getting how internally things have been processed.
**program definition:**Sort name in descending order of there score,if two scores are equal then display names in alphabetic order.
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class Solution {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
Player[] player = new Player[n];
Checker1 checker1 = new Checker1();
for(int i = 0; i < n; i++){
player[i] = new Player(scan.next(), scan.nextInt());
}
scan.close();
Arrays.sort(player, checker1);
for(int i = 0; i < player.length; i++){
System.out.printf("%s %s\n", player[i].name, player[i].score);
}
}
}
class Checker1 implements Comparator<Player> {
#Override
public int compare(Player p1, Player p2) {
String s1=(String)p1.name;
String s2=(String)p2.name;
// TODO Auto-generated method stub
System.out.println(p1.score+"..."+p2.score);
if(p1.score>p2.score){
return -1;
}
else if(p1.score==p2.score){
return s1.compareTo(s2);
}
return 0;
}
}
In order to ensure a consistent result when comparing pairs of elements a, b and b, a the comparison operations need to be consistent, here if p1.score < p2.score you return 0. But, you return -1 if it is greater. That violates the general contract; Java, in many cases, expects to be able to compare the elements in either order. Better to use Integer.compare(int, int) and return the result of comparing names only when that is 0. Like,
#Override
public int compare(Player p1, Player p2) {
System.out.println(p1.score + "..." + p2.score);
int c = Integer.compare(p1.score, p2.score);
if (c == 0) {
return p1.name.compareTo(p2.name);
}
return c;
}

Return Comparator's compare method using a double?

So I have a class to compare the rating of a film. It implements the comparator class as seen below:
public class FilmComparator implements Comparator<Film> {
private Map<Film, List<Rating>> ratings;
public FilmComparator(Map<Film, List<Rating>> ratings) {
this.ratings = ratings;
}
#Override
public int compare(Film o1, Film o2) {
double average1 = average(o1);
double average2 = average(o2);
return average2 - average1; // I cant do this because it need to return an int
}
private double average(Film f) {
int sum = 0;
for (Rating r : ratings.get(f)) {
sum += r.getValue();
}
return sum / ratings.get(f).size();
}
}
As you can see, the average might not always be an integer. I am wondering how I would be able to have a more accurate compare. For example, I am having issues when the average returns 3.6 for one object but 3.0 for the other. To the compare method, the are the same but I need to show a difference. Is this possible?
Simple, let Double do the work for you. Do
return Double.compare(average1, average2); // or swap if desired

Fraction calculator adding

Hi I'm new to java and am working on a Fraction calculator and I am unable to figure out how to get the calculator to reduce simple fractions and add mixed fractions.
Example:
Reduction: 1/2 + -5/6 = -1/3
Mixed Fractions: 4_15/16 + -3_11/16 = 1_1/4
Edit: For mixed fractions, I tried to subtract the numerator from the denominator for num>den to get the whole and the remainder and return it and print but it's not printing out anything.
import java.util.Scanner;
public class Fraction {
public static void main(String[] args) {
System.out.println("Enter an Expression or quit:");
Scanner input = new Scanner(System.in);
String text = input.nextLine();
while (!text.equals("quit")){
String frac1 = text.substring(0,text.indexOf(" "));
String oper = text.substring((text.indexOf(" "))+1,(text.indexOf(" "))+2);
String frac2 = text.substring((text.indexOf(" "))+3);
int fn1 = num(frac1); //frac1 numerator
int fd1 = den(frac1); //frac1 denominator
int fn2 = num(frac2); //frac2 numerator
int fd2 = den(frac2); //frac2 denominator
if (oper.equals("+")){
int sumfinalnum = add(fn1, fd1, fn2, fd2);
if (fd1 == 1 && fd2 == 1){
System.out.println(sumfinalnum);
}
else if ((fn1 + fn2)==0){
System.out.println("0");
}
else if (fd1 == fd2){
if (sumfinalnum>fd1){
System.out.println(extractWholePart(sumfinalnum,fd1)+"_"+extractNumPart(sumfinalnum,fd1)+"/"+fd1);
}
else{
System.out.println(sumfinalnum+"/"+fd1);
}
}
else if (!(fd1 == fd2)){
System.out.println(sumfinalnum+"/"+(fd1*fd2));
}
System.out.println("Enter an Expression or quit:");
text = input.nextLine();
}
}
}
public static int num(String input){
if (input.contains("_")){ //mixed to improper
String a = input.substring(0,input.indexOf("_"));
String b = input.substring((input.indexOf("_"))+1,input.indexOf("/"));
String c = input.substring((input.indexOf("/"))+1);
int a1 = Integer.parseInt(a);
int b1 = Integer.parseInt(b);
int c1 = Integer.parseInt(c);
int d = a1*c1;
int e = d+b1;
return e;
}
else if (!input.contains("/")){
int input1 = Integer.parseInt(input);
return input1;
}
else {
String strnum1 = input.substring(0,input.indexOf("/"));
int num1 = Integer.parseInt(strnum1);
return num1;
}
}
public static int den(String input){
if(!input.contains("/")) { //whole
return 1;
}
String strnum2 = input.substring((input.indexOf("/"))+1);
int num2 = Integer.parseInt(strnum2);
return num2;
}
public static int add(int fn1,int fd1,int fn2,int fd2){
if (fd1 == fd2){ //matching denominator
int numadd = fn1 + fn2;
return numadd;
}
else if (fd1 == 1 && fd2 == 1){ //whole numbers no denom
int sum = fn1 + fn2;
return sum;
}
else if (!(fd1 == fd2)){ //different denominator***
int dencomadd = fd1*fd2;
int gcd1 = dencomadd/fd1;
int gcd2 = dencomadd/fd2;
int comf1num = fn1*gcd1;
int comf2num = fn2*gcd2;
int total = comf1num+comf2num;
return total;
}
else{
return 0;
}
}
public static int extractWholePart(int finalnum, int finalden){
int whole = 0;
while (finalnum > finalden){
whole++;
}
return whole;
}
public static int extractNumPart(int finalnum, int finalden){
while (finalnum > finalden){
finalnum -= finalden;
}
return finalnum;
}
}
Let's start with - It's java, don't be afraid to use bigger variable names. fn1 could very well be called fraction1Numerator.
Next, have a single method to do what it's designed to do. Having an add method that needs four else-ifs in main is not a really good idea.
Creating an object Fraction that would have member variables numerator and denominator would allow your add function to return the entire answer. After all you have the code to add mixed fractions that looks good.
class Fraction{
public int whole;
public int numerator;
public int denominator;
}
I also added "whole" to indicate whole part after simplification. add function would than have signature
public static Fraction add(Fraction fraction1, Fraction fraction2) ...
Extracting whole numbers is simple - subtract denominator from numerator until you can't do that anymore.
public void extractWholePart(Fraction fraction){
int whole = 0;
while (fraction.numerator > fraction.denominator){
whole++;
fraction.numerator -= fraction.denominator;
}
fraction.whole = whole;
}
simplification on the other hand is just dividing both nominator and denominator by the greatest common divisor - algorythm for calculating that is easily findable on the internet.
Try something like this
float mixedToDecimal(String data)
// data would be like this "1 5/8";
String[] parts = data.split(" ");
if(!(parts.lenght > 0)) // this mean that if data is NOT mixedfraction then just return -1
return -1;
float value = Integer.parseInt(parts[0]);
if (parts.length > 1) {
// has fractional part
parts = parts[1].split("/");
float numerator = Integer.parseInt(parts[0]);
float denominator = Integer.parseInt(parts[1]);
value += numerator / denominator;
}
// value contains 1.625
return value;

Getting Max value from x.y.z formatted Number

Is there an easy way of finding the MAX number from the list where number is stored in x.y.z format? e.g. To manage some system versions.
I have tried Collection.max(list) and that does not work.
Sample Code:
public static void main(String args[])
{
List<String> list = new ArrayList<String>();
list.add("1.0.0");
list.add("1.1.0");
list.add("1.9.0");
list.add("1.10.0");
System.out.println(Collections.max(list));
}
Expected: 1.10.0
Result: 1.9
Thanks for your time.
Try to use this one :
Collections.max(myList, new Comparator<String>() {
#Override
public int compare(String lhs, String rhs) {
String[] first = lhs.split("\\.");
String[] second = rhs.split("\\.");
for (int i = 0; i < first.length; i++) {
if(Integer.valueOf(first[i]) > Integer.valueOf(second[i])) {
return 1;
}
if(Integer.valueOf(first[i]) < Integer.valueOf(second[i])) {
return -1;
}
}
return 0;
}
});
Well for one thing, you need to ensure that Java knows they are numbers - at the moment they're just Strings, and strings sort lexigraphically (i.e. in "alphabetical order").
My approach to this would be to create a small class that implements Comparable, which will then work automatically with sorting and comparison logic. Something like this perhaps:
public class VersionNumber implements Comparable<VersionNumber> {
public final int major;
public final int minor;
public final int patch;
// Constructor etc. elided
public int compareTo(VersionNumber other) {
if (other.major != major) return major - other.major;
if (other.minor != minor) return minor - other.minor;
return patch - other.patch;
}
}
Parsing the string to create instances of this class is left as an exercise to the reader!
You may have to write a custom Comparator for comparing version number strings:
public class VersionComparator extends Comparator<String> {
#Override
public int compare(String o1, String o2) {
// Get major/minor/revison numbers by splitting strings at dots
String[] p1 = o1.split("\\.");
String[] p2 = o2.split("\\.");
// Compare major versions then minor then revision until a difference found
for(int i = 0; i < (p1.length < p2.length) ? p1.length : p2.length; i++) {
int result = Integer.valueOf(p1[i]).compareTo(Integer.valueOf(p2[i]));
if(result != 0) return result;
}
// Return zero if they're identical
return 0;
}
}
The you can use this comparator with the Collections.max function:
Collections.max(list, new VarsionComparator());
You can use version of max with the specified comparator:
System.out.println(Collections.max(list, new Comparator<String>() {
public int compare(String s1, String s2)
{
StringTokenizer st1 = new StringTokenizer(s1,".");
StringTokenizer st2 = new StringTokenizer(s2,".");
int res = 0;
String t1, t2;
while(st1.hasMoreTokens() && st2.hasMoreTokens())
{
t1 = st1.nextToken();
t2 = st2.nextToken();
res = Integer.valueOf(t1).compareTo(Integer.valueOf(t2));
}
if(res == 0)
{
res = st1.hasMoreTokens() ? 1 : (st2.hasMoreTokens() ? -1 : 0);
}
return res;
}
public boolean equals(Object obj) { return false; }
}));
This will give you 1.9 because it will not consider second number to be 10, it will treat it as 1 first and then 9
Edit
If you want to do it manually, then
Split your number on basis of "."
Check manually which number is greater.

Categories