How to compare three integer values? - java

I have three integer values along with its text. My requirement is to give rank to all of them.
E.g. I have A = 50 points, B = 500 Points, C = 50 points.
Now I would like to compare all of these and find max and equal values and its according name(like, A/B/C).
EDIT ::
As a output it should return, B = 1st Rank, A = 2nd Rank, C = 2nd Rank.
If anyone has any idea about how can I implement code as per my requirement then, it would be great.
Thanks in advance.
public class ScoreVO implements Comparator<Integer> {
private String playerName = Constants.BLANK_STRING;
private int playerScore;
public String getPlayerName () {
return playerName;
}
public void setPlayerName ( String playerName ) {
this.playerName = playerName;
}
public int getPlayerScore () {
return playerScore;
}
public void setPlayerScore ( int playerScore ) {
this.playerScore = playerScore;
}
#Override
public int compare ( Integer o1, Integer o2 ) {
return o2.compareTo ( o1 );
}
}
Here is my class with Comparator<>.
Please suggest me if I am wrong.

A sample running code which gives output shown below as per your requirement along with player rank. There is a separate method assignRank(List<>) which you can use to assign ranks to players.
Score List: [ScoreVO [playerName=B, playerScore=500, playerRank=1], ScoreVO [playerName=A, playerScore=50, playerRank=2], ScoreVO [playerName=C, playerScore=50, playerRank=2]]
public class ScoreExample {
public static void main(String[] args) {
List<ScoreVO> scoreList = new ArrayList<ScoreVO>();
scoreList.add(new ScoreVO("A", 50));
scoreList.add(new ScoreVO("C", 50));
scoreList.add(new ScoreVO("B", 500));
Collections.sort(scoreList);
assignRank(scoreList);
System.out.println("Score List: "+scoreList);
}
private static void assignRank(List<ScoreVO> scoreList) {
int rank = 0;
int score = 0;
for(ScoreVO scoreVO : scoreList) {
if(score != scoreVO.getPlayerScore()) {
rank++;
scoreVO.setPlayerRank(rank);
score = scoreVO.getPlayerScore();
} else {
scoreVO.setPlayerRank(rank);
}
}
}
}
class ScoreVO implements Comparable<ScoreVO> {
public String playerName;
public int playerScore;
public int playerRank;
public ScoreVO(String playerName, int playerScore) {
this.playerName = playerName;
this.playerScore = playerScore;
}
public String getPlayerName() {
return playerName;
}
public void setPlayerName(String playerName) {
this.playerName = playerName;
}
public int getPlayerScore() {
return playerScore;
}
public void setPlayerScore(int playerScore) {
this.playerScore = playerScore;
}
public int getPlayerRank() {
return playerRank;
}
public void setPlayerRank(int playerRank) {
this.playerRank = playerRank;
}
#Override
public int compareTo(ScoreVO o) {
if(o.getPlayerScore() != getPlayerScore()) {
if(getPlayerScore() > o.getPlayerScore())
return -1;
else
return 1;
}
return getPlayerName().compareTo(o.getPlayerName());
}
#Override
public String toString() {
return "ScoreVO [playerName=" + playerName + ", playerScore="
+ playerScore + ", playerRank=" + playerRank + "]";
}
}

ScoreVO should implement Comparable<ScoreVO>. And your compareTo method looks like this:
#Override
public int compareTo ( ScoreVO o ) {
if(playerScore != o.playerScore)
return Integer.compare(playerScore, o.playerScore);
return playerName.compareTo(o.playerName);
}

You should implment Comparable for ordering purpuses, and equals() for equation (that can use compareTo)
like this
public class ScoreVO implements Comparable<ScoreVO> {
#Override
public int compareTo(ScoreVO other) {
return other == null ? 1 : getPlayerScore() - other.getPlayerScore();
}
#Override
public boolean equals(object other) {
return !(other instanceof ScoreVO) ? false : compareTo(other) == 0 ;
}
}
However, you probably want to compare equality based on player name. think of putting ScoreVO object in a map - what is the key? so -
#Override
public boolean equals(object other) {
return other == null || !(other instanceof ScoreVO) ? false :
getPlayerName.equals(other.getPlayerName()) ;
}

As there are just three values, it is possible to hard-code all operations. You can think of a very compact and efficient way to work this out.
Every comparison of two values can give an outcome >, = or <. Assigning the value 0, 1 or 2 to these, you can pack the three comparisons in a single number using base 3 encoding. You will end up with a number in range 0 to 26, and every different value corresponds to a different answer that you can tabulate (or process in a switch statement).
int Compare(int A, int B) { return A > B ? 0 : (A == B ? 1 : 2); }
char* Answer[27]= { "A1B2C3", "A1B1C3", "B1A2C3", ... }; // To be filled
return Answer[Compare(A, B) + 3 * compare(B, C) + 9 * compare(A, C)];

Related

Sort collection not working as expected

I don't know why my list is not sorted.
I'm using Collection.sort, it seems to do the job but when I launch the UnitTest it outputs an error.
Expected :characterWithMaxVotes [voteCount : 100]
Actual :characterMiddle75[voteCount : 75]
//Exact same method as in the Character class (pasted for better readability on SO question)
public static void sortCharactersByVotes(List<Character> lstCharacters) {
Collections.sort(lstCharacters, new Comparator<Character>() {
#Override
public int compare(Character character, Character p1) {
int result = (character.getVoteCount() > p1.getVoteCount()) ? 1 : 0;
return result;
}
});
}
#Test
public void sortCharactersByVoteCounts() {
Character characterWithMinVotes = Character.newBuilder().name("characterWithMinVotes").voteCount(0).build();
Character characterMiddle25 = Character.newBuilder().name("characterMiddle25").voteCount(25).build();
Character characterMiddle75 = Character.newBuilder().name("characterMiddle75").voteCount(75).build();
Character characterWithMaxVotes = Character.newBuilder().name("characterWithMaxVotes").voteCount(100).build();
List<Character> lstCharacters = new ArrayList<>();
lstCharacters.add(characterMiddle75);
lstCharacters.add(characterWithMaxVotes );
lstCharacters.add(characterMiddle25);
lstCharacters.add(characterWithMinVotes);
sortCharactersByVotes(lstCharacters);
System.out.print(lstCharacters);
assertEquals(lstCharacters.get(0), characterWithMaxVotes);
assertEquals(lstCharacters.get(1), characterMiddle75);
assertEquals(lstCharacters.get(2), characterMiddle25);
assertEquals(lstCharacters.get(3), characterWithMinVotes);
}
How to do it properly, thank you for your help.
PS : as requested, here is my Character class
public class Character {
private static final String TAG = "Character";
private int id;
private String name = "";
public int voteCount;
public boolean isVotedByUser = false;
public int getId() {
return id;
}
public int getVoteCount() {
return voteCount;
}
public String getName() {
return name;
}
public static CharacterBuilder newBuilder(){
return new CharacterBuilder();
}
#Override
public String toString() {
return name + "[voteCount : " + voteCount + "]";
}
public static void sortCharactersByVotes(List<Character> lstCharacters) {
Collections.sort(lstCharacters, new Comparator<Character>() {
#Override
public int compare(Character character, Character p1) {
int result = (character.getVoteCount() > p1.getVoteCount()) ? 1 : 0;
return result;
}
});
}
public static class CharacterBuilder {
public Character character;
CharacterBuilder() {
character = new Character();
}
public CharacterBuilder id(int id) {
character.id = id;
return this;
}
public CharacterBuilder name(String name) {
character.name = name;
return this;
}
public CharacterBuilder voteCount(int voteCount) {
character.voteCount = voteCount;
return this;
}
public Character build() {
return character;
}
}
}
(edited to use Integer.compare as suggested)
The compare method must return 0 if and only if the two compared objects have equal "rank" (in your case, equal vote count), otherwise must return a positive value if a>b or negative if b>a (or vice versa, according to the wanted sort direction).
To solve this simply, you can write (assuming getVoteCount() is int):
public int compare(Character character, Character p1) {
return Integer.compare(p1.getVoteCount(), character.getVoteCount());
}
(to reverse the sort result, just swap the operands)
The implementation of your Comparator is not correct, as you want to have highest value first (and not the opposite lowest value first), you are supposed to return a positive value if character.getVoteCount() < p1.getVoteCount() and a negative value if character.getVoteCount() > p1.getVoteCount(), you should use Integer.compare(int x, int y) to compare the values of getVoteCount() (assuming that it returns an int) such that your Comparator could be :
new Comparator<Character>() {
#Override
public int compare(Character c1, Character c2) {
return Integer.compare(c2.getVoteCount(), c1.getVoteCount());
}
}
NB: Don't compare the values of getVoteCount() with a simple subtraction otherwise you will take the risk to get incorrect results as it is prone to overflow issues.
I think that is better to change a little bit the comparator implemented. Try:
public static void sortCharactersByVotes(List<Character> lstCharacters) {
Collections.sort(lstCharacters, new Comparator<Character>() {
#Override
public int compare(Character character, Character p1) {
int result = (character.getVoteCount() - p1.getVoteCount());
return result;
}
});
}
Another thing is that you are adding twice the
characterWithMaxVotes
Hope it helps!
You sort of comparison method shall be modified to
public static void sortCharactersByVotes(List<Character> lstCharacters) {
lstCharacters.sort(Comparator.comparingInt(Character::getVoteCount));
}
Note - The comparison is based on the integer getVoteCount of Character and this is supported in Java 8+.

Finding the most suitable objects by set of parameters in java

I have a set of objects. This objects calculate some numbers based on request parameters. Let's call them calculators. Each calculator has description where specified type of requests that this calculator the most suitable for.
For example,
Calculator1 : with this parameters : price > 10, gender = male, geo_id = 1, 2 or 3.
Calculator2 : with this parameters : price < 5, gender = male, geo_id = 1, 2.
For request : price = 11, gender = male, geo_id = 2 I should get calculator1 like the most suitable and then calculator2.
For request : price = 4, gender = male, geo_id = 2 I should get calculator2 and then calculator1.
For request : price = 3, gender = female, geo_id = 5 I should get only the second one.
Now I'm doing it with Lucene, but it's not really fit for this task. Can you recommend me some library or approach?
My suggestion would be to use a comparator. See a sketch of the classes below.
import java.util.HashMap;
import java.util.Map;
public abstract class Calculator {
public static Map<String, Integer> weights;
static {
weights = new HashMap<String, Integer>();
weights.put("price", 10);
weights.put("gender", 2);
weights.put("geo", 5);
}
public abstract int calculate(Map<String, Integer> request);
public abstract int fitnessFor(Map<String, Integer> request);
}
You can use the weights to adjust relative importance of the individual request parameters.
import java.util.Map;
public class Calculator1 extends Calculator {
public int calculate(Map<String, Integer> request) {
return -1;
}
#Override
public int fitnessFor(Map<String, Integer> request) {
int fitness = -1;
Integer price = request.get("price");
if (price == null)
return fitness;
if (price > 10)
fitness += weights.get("price");
return fitness;
}
public String toString() { return "Calculator1"; }
}
Calculator1 cares only about the pricey items.
import java.util.Map;
public class Calculator2 extends Calculator {
public int calculate(Map<String, Integer> request) {
return -1;
}
#Override
public int fitnessFor(Map<String, Integer> request) {
int fitness = -1;
Integer price = request.get("price");
if (price == null)
return fitness;
if (price < 5)
fitness += weights.get("price");
Integer gender = request.get("gender");
if (gender == null)
return fitness;
if (gender == 1)
fitness += weights.get("gender");
return fitness;
}
public String toString() { return "Calculator2"; }
}
Calculator2 cares about the less pricey items esp. if they are for gender 1.
The comparator just compares Calculators by their fitness relative to the request:
import java.util.Comparator;
import java.util.Map;
public class CalcComparator implements Comparator<Calculator> {
private Map<String, Integer> request;
public CalcComparator(Map<String, Integer> request) {
this.request = request;
}
#Override
public int compare(Calculator c1, Calculator c2) {
int c1Fitness = c1.fitnessFor(request);
int c2Fitness = c2.fitnessFor(request);
if (c1Fitness == c2Fitness)
return 0;
if (c1Fitness < c2Fitness)
return 1;
return -1;
}
}
Try it out with:
public class Main {
public static void main(String[] args) {
Map<String, Integer> request = new HashMap<String, Integer>();
request.put("price", 5);
request.put("gender", 1);
List<Calculator> calculators = new ArrayList<Calculator>();
calculators.add(new Calculator1());
calculators.add(new Calculator2());
Collections.sort(calculators, new CalcComparator(request));
System.out.println("For request: "+request);
for (Calculator c : calculators) {
System.out.println("\t"+c.toString() + "( fitness " + c.fitnessFor(request) + ")");
}
}
}
This is just a sketch to illustrate the idea. You will probably want to introduce an enum for the request parameters, maybe introduce a Request class, most likely change completely how fitness is computed, make some of the fields private and encapsulate them, etc.
The advantage is that you easily get an ordering of all the Calculators based on their fitness for the request.
Provided that I understood you correctly, I would suggest that you use the Specification design pattern which is used in cases like this. There's no need in such a fancy library like Lucene for such a simple task. The advantage of the Specification pattern is that it keeps all the filtering logic grouped and encapsulated. Your implementation may vary, but below is a simple example of what it could look like
public interface Specification<T> {
boolean isSatisfiedBy(T candidate);
Specification<T> and(Specification<T> specification);
Specification<T> or(Specification<T> specification);
Specification<T> not(Specification<T> specification);
}
public abstract class Calculator {
// ...
}
public class Calculator1 extends Calculator implements Specification<Request> {
public boolean isSatisfiedBy(Request request) {
// check if the request fits this calculator
}
}
public class Calculator2 extends Calculator implements Specification<Request> {
public boolean isSatisfiedBy(Request request) {
// check if the request fits this calculator
}
}
You can then have a collection or a pool of calculators such that
public class Calculators {
private final List<RequestSpecification> calculators;
public Calculator getOneSuitedFor(Request request) {
for (Calculator calculator : calculators) {
if (calculator.isSatisfiedBy(request)) {
return calculator;
}
}
return null;
}
}
And here how you would use it
Calculator calculator = Calculators.getOneSuitedFor(request);
Or, if needed, you can always go on and expand on it by making use of composition (see the reference link above) which allows for logic chaining and combining of different specifications depending on the context. This, however, would require a little bit different class design from that of above, but is more flexible
final Request request;
Specification<Calculator> price = new Specification<>() {
public boolean isSatisfiedBy(Calculator calculator) {
return calculator.supportsPrice(request.getPrice());
}
};
Specification<Calculator> gender = new Specification<>() {
public boolean isSatisfiedBy(Calculator calculator) {
return calculator.supportsGender(request.getGender());
}
};
Specification<Calculator> region = new Specification<>() {
public boolean isSatisfiedBy(Calculator calculator) {
return calculator.supportsRegion(request.getRegion());
}
};
Specification calcSpec = price.and(gender).and(region);
boolean isSatisfied = calcSpec.isSatisfiedBy(calculator);
Another interesting example is to use named specifications
Specification<Calculator> teenager = new Specification<>() {
public boolean isSatisfiedBy(Calculator calculator) {
return calculator.getAge() >= 13 && calculator.getAge() <= 19;
}
};
Specification<Calculator> male = new Specification<>() {
public boolean isSatisfiedBy(Calculator calculator) {
return calculator.getGender().equals("male");
}
};
Specification<Calculator> fromEurope = new Specification<>() {
public boolean isSatisfiedBy(Calculator calculator) {
return calculator.getRegion().equals("Europe");
}
};
Specification<Calculator> calcSpec = teenager.and(male).and(fromEurope);
boolean isSatisfied = calcSpec.isSatisfiedBy(calculator);
You could maybe try something like this:
public enum Calculator
{
CALC1
{
#Override
protected int matchCount( Map parameters )
{
// TODO count how many conditions match
return 0;
}
#Override
protected int calc( Map parameters )
{
// TODO
return 0;
}
},
CALC2
{
#Override
protected int matchCount( Map parameters )
{
// TODO count how many conditions match
return 0;
}
#Override
protected int calc( Map parameters )
{
// TODO
return 0;
}
};
protected abstract int matchCount( Map parameters );
protected abstract int calc( Map parameters );
public int doCalc( Map parameters )
{
Calculator mostSuited = null;
int maxCount = 0;
for ( Calculator calc : values() )
{
int matchCount = calc.matchCount( parameters );
if ( matchCount > maxCount )
{
mostSuited = calc;
}
}
return mostSuited.calc( parameters );
}
}
The way you would use the above is by invoking: int result = Calculator.doCalc( parameters )
Create a Calculator base class :
public static abstract class Calculator {
// This Contains the common score calculation methods.
public int getScore(int price, String gender, int geo_id) {
int score = 0;
if (gender.equalsIgnoreCase("male"))
score++;
if (getGeoIds().contains(geo_id))
score++;
return score;
}
public ArrayList<Integer> getGeoIds() {
// Fetching the common list of geo points to be compared.
ArrayList<Integer> lst = new ArrayList<Integer>();
lst.add(1);
lst.add(2);
return lst;
}
public abstract void doCalculation();
}
Then create your calculator classes by extending from this base.
public static class Calcualtor1 extends Calculator {
#Override
public int getScore(int price, String gender, int geo_id) {
// fetching score from common score calculation.
int score = super.getScore(price, gender, geo_id);
// Adding its own score logic.
if (price > 10)
score++;
return score;
}
#Override
public void doCalculation() {
// Do your actual work.
}
#Override
public ArrayList<Integer> getGeoIds() {
ArrayList<Integer> lst = super.getGeoIds();
// Adding the geo id to compare for this calculator.
lst.add(3);
return lst;
}
}
public static class Calcualtor2 extends Calculator {
#Override
public int getScore(int price, String gender, int geo_id) {
// fetching score from common score calculation.
int score = super.getScore(price, gender, geo_id);
// Adding its own score logic.
if (price < 5)
score++;
return score;
}
#Override
public void doCalculation() {
// Do your actual work.
}
}
Initialise values :
//To store the list of available calculators.
private static ArrayList<Class<? extends Calculator>> calculators;
static {
//Initializing the calculator list in static constructor.
calculators = new ArrayList<Class<? extends Calculator>>();
calculators.add(Calcualtor1.class);
calculators.add(Calcualtor2.class);
}
Actual processing :
public static void main(String[] args) {
int price = 10;
String gender = "male";
int geo_id = 2;
Calculator calculator = null;
int score = 0;
for (Class<? extends Calculator> calClass : calculators) {
Calculator cal = null;
try {
cal = calClass.newInstance();
} catch (Exception e) {
continue;
}
int calScore = cal.getScore(price, gender, geo_id);
if (calScore > score) {
calculator = cal;
score = calScore;
}
}
if (calculator != null) {
calculator.doCalculation();
}
}

How to use CompareTo to sort the PlaneMap by Ascending and Descending order

Im trying to sort my planes by Ascending and Descending order. I have a hashmap of planes and i want to compare them so that i can get the next plane due and last plane due by sorting the map by timeLimitBeforeLand. I wrote a compareTo method which looks like :
//---------------------------------------------------------------------------------------
// CompareTo() used with the Comparable implementation.
//---------------------------------------------------------------------------------------
public int compareTo(Object arg0)
{
if((arg0 != null) && (arg0 instanceof Plane))
{
Plane p = (Plane) arg0;
return (int)Math.ceil(this.timeLimitBeforeLand - p.getLimitBeforeLand());
}
return 0;
}
CompareTo takes timeLimitBeforeLand:
// ---------------------------------------------------------------------------------------
// Name: getTimeLimitBeforeLand.
// Description: Get the time before every plane is going to land.
//---------------------------------------------------------------------------------------
public double getTimeLimitBeforeLand()
{
double fuelConsumption;
double timeLimitBeforeLand = 0;
for (TreeMap<String, Plane> theEntry : airlineMap.values()) {
for (Plane aPlane : theEntry.values()) {
if (aPlane.getPlaneType() == aPlane.getPlaneType().AIRBUS) {
System.out.println(" ");
System.out.println(aPlane);
fuelConsumption = 2;
timeLimitBeforeLand = (double) (aPlane.getFuelRemaining() / fuelConsumption);
System.out.println(timeLimitBeforeLand + " minutes to land.");
System.out.println(" ");
} else if (aPlane.getPlaneType() == aPlane.getPlaneType().CORPORATE) {
System.out.println(" ");
System.out.println(aPlane);
fuelConsumption = 3;
timeLimitBeforeLand = (aPlane.getFuelRemaining() / fuelConsumption);
System.out.println(timeLimitBeforeLand + " minutes to land.");
System.out.println(" ");
} else if (aPlane.getPlaneType() == aPlane.getPlaneType().PRIVATE) {
System.out.println(" ");
System.out.println(aPlane);
fuelConsumption = 4;
timeLimitBeforeLand = (double) (aPlane.getFuelRemaining() / fuelConsumption);
System.out.println(timeLimitBeforeLand + " minutes to land.");
System.out.println(" ");
}
}
}
return timeLimitBeforeLand;
}
My attempt so far in the mainApp:
TreeMap<String, PlaneStore> map = new TreeMap<String, PlaneStore>();
ArrayList<Plane> copyList = new ArrayList<Plane>(map.);
Plane comp = new Plane();
Collections.sort(copyList, plane);
Plane Class:
//---------------------------------------------------------------------------------------
// Name: Imports.
// Description: To allow the use of different Java classes.
//---------------------------------------------------------------------------------------
import java.io.Serializable;
//---------------------------------------------------------------------------------------
//Name: Class declaration.
//---------------------------------------------------------------------------------------
public class Plane implements Comparable, Serializable
{
//---------------------------------------------------------------------------------------
// Variable declarations.
//---------------------------------------------------------------------------------------
private String flightNumber;
public String airlineName;
private double fuelRemaining;
private int overdue;
private int passengerNumber;
//---------------------------------------------------------------------------------------
// Enum declaration.
//---------------------------------------------------------------------------------------
private AIRPLANETYPE planeType;
private boolean isLanded = false;
public double timeLimitBeforeLand;
//---------------------------------------------------------------------------------------
// Enum Constuctor.
//---------------------------------------------------------------------------------------
public enum AIRPLANETYPE
{
AIRBUS("1"), CORPORATE("2"), PRIVATE("3");
private String planeName;
private AIRPLANETYPE(String planeName)
{
this.planeName = planeName;
}
public String getPlaneName()
{
return this.planeName;
}
}
//---------------------------------------------------------------------------------------
// Constructor.
//---------------------------------------------------------------------------------------
public Plane(String flightNumber, String airlineName,
double fuelRemaining, int overdue, int passengerNumber,
AIRPLANETYPE planeType, boolean isLanded)
{
this.flightNumber = flightNumber;
this.airlineName = airlineName;
this.fuelRemaining = fuelRemaining;
this.passengerNumber = passengerNumber;
this.overdue = overdue;
this.planeType = planeType;
this.isLanded = isLanded;
}
//---------------------------------------------------------------------------------------
// Getters and Setters.
//---------------------------------------------------------------------------------------
public String getAirlineName()
{
return airlineName;
}
public void setAirlineName(String airlineName)
{
this.airlineName = airlineName;
}
public void setOverdue(int overdue)
{
this.overdue = overdue;
}
public int getOverdue()
{
return overdue;
}
public String getFlightNumber()
{
return flightNumber;
}
public void setFlightNumber(String flightNumber)
{
this.flightNumber = flightNumber;
}
public double getFuelRemaining()
{
return fuelRemaining;
}
public void setFuelRemaining(double fuelRemaining)
{
this.fuelRemaining = fuelRemaining;
}
public int getPassengerNumber()
{
return passengerNumber;
}
public void setPassengerNumber(int passengerNumber)
{
this.passengerNumber = passengerNumber;
}
public AIRPLANETYPE getPlaneType()
{
return planeType;
}
public void setPlaneType(AIRPLANETYPE planeType)
{
this.planeType = planeType;
}
public boolean isLanded()
{
return isLanded;
}
public void setLanded(boolean isLanded)
{
this.isLanded = isLanded;
}
public double getLimitBeforeLand()
{
return timeLimitBeforeLand;
}
public void setTimeLimitBeforeLand(double timeLimitBeforeLand)
{
this.timeLimitBeforeLand = timeLimitBeforeLand;
}
//---------------------------------------------------------------------------------------
// CompareTo() used with the Comparable implementation.
//---------------------------------------------------------------------------------------
public int compareTo(Object arg0)
{
if((arg0 != null) && (arg0 instanceof Plane))
{
Plane p = (Plane) arg0;
return (int)Math.ceil(this.timeLimitBeforeLand - p.getLimitBeforeLand());
}
return 0;
}
//---------------------------------------------------------------------------------------
// toString().
//---------------------------------------------------------------------------------------
public String toString()
{
return "Plane: flightNumber=" + flightNumber + "."
+ " airlineName=" + airlineName + "."
+ " fuelRemaining=" + fuelRemaining + " litres."
+ " overdue=" + overdue + " minutes."
+ " passengerNumber="+ passengerNumber + "."
+ " airplaneType=" + planeType +
"hasLanded=" + isLanded+ ".\n";
}
}
The second argument in Collections.sort is for a Comparator not a Plane. Since I saw no mention of a Comparator, you should be able to use the natural order (defined by the compareTo method in your Plane object) and not have a second argument in the Collections.sort
EDIT: Unless you have just excluded that code, you aren't creating any Plane instances and you're using empty collections here...
TreeMap<String, PlaneStore> map = new TreeMap<String, PlaneStore>();
ArrayList<Plane> copyList = new ArrayList<Plane>(map.);
and you will be sorting by PlaneStores so you have to obtain all the Planes in each PlaneStore and add them to your copyList before sorting.
I would consider researching each of the Collections a little more and deciding what the best one for your need would be.

Comparison method violates its general contract in sorting method

I get an error in my sorting method.
Comparison method violates its general contract
This is my sorting object with sort method
public abstract class ComparablePerson extends IDValueItem implements
Comparable<ComparablePerson> {
private int score;
private String itemID,itemName;
//setters and getters
public int compareTo(ComparablePerson another) {
if (score == another.getScore())
return this.getItemName().compareToIgnoreCase(another.getItemName());
else if ((score) > another.getScore())
return 1;
else
return -1;
}
#Override
public boolean equals(Object o) {
final ComparablePerson other = (ComparablePerson) o;
if (score == other.getScore() && this.getItemName().equalsIgnoreCase(other.getItemName()))
return true;
else
return false;
}
I just call
Collections.sort(ComparablePersonCollection);
What can be the cause of this?
The compareTo and equals method implementations seem to be inconsistent, the error is telling you that for the same two objects equals gives true while compareTo does not produce zero, which is incorrect. I suggest you invoke compareTo from equals to ensure consistency or otherwise define a custom Comparator<T>.
Simply do:
public abstract class ComparablePerson extends IDValueItem implements Comparable<ComparablePerson> {
private int score;
private String itemID,itemName;
//setters and getters
public int compareTo(ComparablePerson another) {
if (score == another.getScore())
return this.getItemName().compareToIgnoreCase(another.getItemName());
else if ((score) > another.getScore())
return 1;
else
return -1;
}
#Override
public boolean equals(Object o) {
return compareTo(o) == 0;
}
}
ComparablePerson is abstract, the comparison method is probably overloaded elsewhere...
Can you post the client (which owns the collection) and the concrete classes?
This code works well:
public class ComparablePerson implements Comparable< ComparablePerson > {
public ComparablePerson( int score, String name ) {
_score = score;
_itemName = name;
}
#Override public int compareTo( ComparablePerson another ) {
int delta = _score - another._score;
if( delta != 0 ) return delta;
return _itemName.compareToIgnoreCase( another._itemName );
}
#Override public boolean equals( Object o ) {
return 0 == compareTo((ComparablePerson)o);
}
#Override public int hashCode() {
return super.hashCode();
}
private final int _score;
private final String _itemName;
public static void main( String[] args ) {
List< ComparablePerson > oSet = new LinkedList<>();
oSet.add( new ComparablePerson( 5, "x" ));
oSet.add( new ComparablePerson( 5, "y" ));
oSet.add( new ComparablePerson( 5, "z" ));
oSet.add( new ComparablePerson( 6, "x" ));
oSet.add( new ComparablePerson( 6, "y" ));
oSet.add( new ComparablePerson( 6, "z" ));
Collections.sort( oSet );
System.err.println( "Ok" );
}
}

Polymorphism and pre validating class attributes

Basically I have been tasked with tackling the following scenario:
When you are designing your class/es, you have to decide what attributes and methods you will include in. For example, if you decide to work in millimeters, your size variable (length) could be of type integer (but later, when calculating the cost, you will have to convert the volume into square inches, because the cost is given per cubic inch of plastic (Table 2 and Table 3 of the coursework)). The volume of plastic material used will be the difference between the outer and inner volume of a pipe. If you decided to prompt the length in meters, then the type should be double, or float, etc.
Once you have validated the user order, your program should determine, based on Table 1, what is the type of the ordered pipe.
Table 1. Types of plastic pipes available.
Type Plastic’s grade Colour print Inner insulation Outer reinforcement Chemical resistance
0 1 2
I 1 – 3 YES NO NO NO NO YES/NO
II 2 – 4 NO YES NO NO NO YES/NO
III 2 – 5 NO NO YES NO NO YES/NO
IV 2 – 5 NO NO YES YES NO YES/NO
V 3 – 5 NO NO YES YES YES YES/NO
That's all fine but the part that is getting me is this bit here:
Say in your main class you have determined that client’s order is a pipe of type I, then you can create an object of TypeI and for this object you can call the cost() method to calculate the cost and to show it to the user.
It is basically asking to not instantiate any objects before figuring out which one you need to instantiate, which is hard when it classes a big if statement in the verification as a 'Brute force method'.
Here is what I have so far.
Main
public class Cw1 {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
ArrayList<Pipe> pipeList = new ArrayList<Pipe>();
// TODO code application logic here
Grade g1 = new Grade(1,3,true,false,false,false,false);
Grade g2 = new Grade(2,4,false,true,false,false,false);
Grade g3 = new Grade(2,5,false,false,true,false,false);
Grade g4 = new Grade(2,5,false,false,true,true,false);
Grade g5 = new Grade(3,5,false,false,true,true,true);
pipeList.add(g1);
pipeList.add(g2);
pipeList.add(g3);
pipeList.add(g4);
pipeList.add(g5);
for (Pipe p: pipeList)
{
p.setGrade(1);
p.setColour0(false);
p.setColour1(false);
p.setColour2(true);
p.setIns(true);
p.setReinf(true);
p.validate();
}
}
}
Grade (It must have abstracting in the solution)
public class Grade extends Pipe {
public Grade(int minGrade, int maxGrade, boolean hasColour0, boolean hasColour1, boolean hasColour2, boolean hasIns, boolean hasReinf) {
super(minGrade, maxGrade, hasColour0, hasColour1, hasColour2, hasIns, hasReinf);
}
}
And pipe
public abstract class Pipe {
public boolean isChemRes() {
return chemRes;
}
public void setChemRes(boolean chemRes) {
this.chemRes = chemRes;
}
public boolean isColour0() {
return colour0;
}
public void setColour0(boolean colour0) {
this.colour0 = colour0;
}
public boolean isColour1() {
return colour1;
}
public void setColour1(boolean colour1) {
this.colour1 = colour1;
}
public boolean isColour2() {
return colour2;
}
public void setColour2(boolean colour2) {
this.colour2 = colour2;
}
public double getDiameter() {
return diameter;
}
public void setDiameter(double diameter) {
this.diameter = diameter;
}
public boolean isIns() {
return ins;
}
public void setIns(boolean ins) {
this.ins = ins;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public boolean isReinf() {
return reinf;
}
public void setReinf(boolean reinf) {
this.reinf = reinf;
}
public Pipe(int minGrade, int maxGrade, boolean hasColour0, boolean hasColour1, boolean hasColour2, boolean hasIns, boolean hasReinf) {
this.minGrade = minGrade;
this.maxGrade = maxGrade;
this.hasColour0 = hasColour0;
this.hasColour1 = hasColour1;
this.hasColour2 = hasColour2;
this.hasIns = hasIns;
this.hasReinf = hasReinf;
}
public Pipe() {
}
//<editor-fold desc="Class variables">
private int grade;
private double length, diameter;
private boolean colour0, colour1, colour2, ins, reinf, chemRes;
private int minGrade, maxGrade;
private boolean hasColour0, hasColour1, hasColour2, hasIns, hasReinf;
// </editor-fold>
public int getGrade() {
return grade;
}
public void setGrade(int grade) {
this.grade = grade;
}
//<editor-fold desc="Public Methods">
public double calcVol()
{
return 0;
}
public double calcCost()
{
return 0;
}
public void validate()
{
if ((grade >= minGrade && grade <= maxGrade) & (colour0 == true && hasColour0 || colour1 == true && hasColour1 || colour2 == true && hasColour2) && (ins == hasIns) && (reinf == hasReinf))
{
System.out.print("True");
}
else
{
System.out.print("False");
}
}
// </editor-fold>
}
So basically, I don't understand how I could achieve the same result without instantiating the objects before hand and validating them?
The class isn't high level, we have only just learned polymorphism.
Usually, the data which tells you which objects to create comes from an external source: a file, a socket, another object etc. In your case, you could use a text file. Create the Grade instances passing the values you read to the constructor and then call validate and cost on each.
public class PipeFactory(){
public Pipe CreatePipe( int minGrade, int maxGrade, boolean hasColour0, boolean hasColour1, boolean hasColour2, boolean hasIns, boolean hasReinf ){
if( (minGrade == 1 || maxGrade == 3) /* ... Complete this condition yourself */ )
return new TypeIPipe();
if( (minGrade == 2 || maxGrade == 4 /* ... Complete this condition yourself */ )
return new TypeIIPipe();
//If for other types...
//If no pipe was created, parameters are invalid, so we throw an exception
throw new InvalidArgumentException( "Can't create a pipe with these parameters" );
}
}

Categories