I have a java Class SalesDataJson as shown below. The different status values are 'READY', 'PICKED' and 'PACKED'.
SalesDataJson.java
public class SalesDataJson {
private Long salesOrderNumber;
private String status;
}
Now i want to order the 'SalesDataJson' object in the order of the status 'READY','PICKED' and 'PACKED'. Can anyone please help me with this.
I have the done the below code but it is not working:-
public void sort(){
Collections.sort(salesDataJsons, new Comparator<SalesDataJson>() {
#Override
public int compare(SalesDataJson o1, SalesDataJson o2) {
if (o1.getStatus() == PackagingStatus.RTW && o2.getStatus() == PackagingStatus.PICKED)
return -1;
else if (o1.getStatus() == PackagingStatus.PICKED && o2.getStatus() == PackagingStatus.RTW)
return 1;
else if (o1.getStatus() == PackagingStatus.RTW && o2.getStatus() == PackagingStatus.PACKED)
return -1;
else if (o1.getStatus() == PackagingStatus.PACKED && o2.getStatus() == PackagingStatus.RTW)
return 1;
else if (o1.getStatus() == PackagingStatus.PICKED && o2.getStatus() == PackagingStatus.PACKED)
return -1;
else if (o1.getStatus() == PackagingStatus.PACKED && o2.getStatus() == PackagingStatus.PICKED)
return 1;
return 0;
}
});
}
Make a helper method like this:
int getSortOrder(String status) {
switch(status) {
case PackagingStatus.RTW: 1; break;
case PackagingStatus.PICKED: 2; break;
case PackagingStatus.PACKED: 3; break;
default:
throw new RuntimeException("Unknown status" + status);
}
}
then you can do
new Comparator<SalesDataJson>() {
#Override
public int compare(SalesDataJson o1, SalesDataJson o2) {
return Integer.compare(getSortOrder(o1.getStatus), getSortOrder(o2.getStatus)));
}
}
If your PackagingStatus enum is defined in this way (ordered the way you like):
public enum PackagingStatus{
RTW, PICKED, PACKED;
}
you could just use ordinal() which returns the position in the enumeration.
public void sort(){
Collections.sort(salesDataJsons, new Comparator<SalesDataJson>() {
#Override
public int compare(SalesDataJson o1, SalesDataJson o2) {
return (o1.getStatus().ordinal() - o2.getStatus().ordinal());
}
});
}
Anyway, this is not really recommended since it is brittle, a small re-ordering could break your sorting.
You could attach this sorting logic in a helper class (as #Stephen Friedrich) suggested or directly into the enum itself (even if using a String status is again not ideal, I would replace it with PackagingStatus directly):
public enum PackagingStatus {
PICKED(1), PACKED(2), RTW(3);
PackagingStatus(int position) {
this.position = position;
}
private final int position;
public int getPosition() {
return position;
}
}
Then the sort becomes:
public void sort(){
Collections.sort(salesDataJsons, new Comparator<SalesDataJson>() {
#Override
public int compare(SalesDataJson o1, SalesDataJson o2) {
return (o1.getStatus().getPosition() - o2.getStatus().getPosition());
}
});
}
Of course, if you'd like to write and call the sort using java8, this is the equivalent using lambda expressions:
Collections.sort(
salesDataJsons,
(o1, o2) ->
o1.getStatus().getPosition() - o2.getStatus().getPosition()
);
You just arrange the statuses in the order you like and
then your sorting comes easy as this:
List<SalesDataJson> sortedList = orignalList.stream()
.sorted(Comparator.comparing(SalesDataJson::getStatus))
.collect(Collectors.toList());
Related
I need to write abstract class, which looks like this.
public abstract class Value {
public abstract String toString();
public abstract Value add(Value v);
public abstract Value sub(Value v);
public abstract boolean eq(Value v);
public abstract boolean lte(Value v);
public abstract boolean gte(Value v);
public abstract boolean neq(Value v);
public abstract boolean equals(Object other);
public abstract int hashCode();
public abstract Value create(String s);
}
Now I need to make few classe, which inherit from that one. I started from Int class and implemented it like this:
public class Int extends Value {
int val;
public String toString() {
String toStr = Integer.toString(val);
return toStr;
}
public Int add(Value v) {
Int result = new Int();
if(v instanceof Int) {
Int temp = (Int) v;
result.val = val + temp.val;
}
return result;
}
public Int sub(Value v) {
Int result = new Int();
if(v instanceof Int) {
Int temp = (Int) v;
result.val = val - temp.val;
}
return result;
}
public boolean eq(Value o) {
if(this == o) return true;
if(this == null) return false;
if(getClass() != o.getClass()) return false;
Int other = (Int) o;
return toString() == other.toString();
}
public boolean lte(Value v) {
if(v instanceof Int) {
Int temp = (Int) v;
return this.val < temp.val;
}
return false;
}
public boolean gte(Value v) {
if(v instanceof Int) {
Int temp = (Int) v;
return this.val > temp.val;
}
return false;
}
public boolean neq(Value v) {
if(v instanceof Int) {
Int temp = (Int) v;
return !eq(temp);
}
return true;
}
public boolean equals(Object o) {
if(this == o) return true;
if(this == null) return false;
if(getClass() != o.getClass()) return false;
Int other = (Int) o;
return toString() == other.toString();
}
public int hashCode() {
Integer hash = val;
return hash.hashCode();
}
public Int create(String s) {
val = Integer.parseInt(s);
return this;
}
}
Everything is compiling and working, but I have no clue if my hashcode() function and equals() are good. Furthermore i want to use create() to make objects like this:
getInstance().create("1234");
Is my method also sufficient?
Everything is compiling and working, but I have no clue if my hashcode() function and equals() are good.
Your equals() should compare int val and not result of toString() of compared objects (this.val == other.val).
Your hashCode() looks good, though I would add #Override to it (same with equals()).
Furthermore i want to use create() to make objects like this: getInstance().create("1234");
Looking at its implementation, it looks fine (i.e. would work according to your needs):
public Int create(String s) {
val = Integer.parseInt(s);
return this;
}
though I don't think you really want to use it with getInstance(). Simply Int.create() would be enough:
public static Int create(String s) {
val = Integer.parseInt(s);
return new Int(val);
}
Note that you would need a private constructor.
Also, as someone noted in the comments, consider using generics instead of inheritance.
The hashCode() method is fine (although I'd add an #Override annotation, just to make the code easier to maintain and avoid mistakes), but the equals(Object) definitely isn't.
Following the logic you have in place, == isn't the right way to compare strings. You should use equals instead (see, e.g., How do I compare strings in Java?). In addition, as Joakim Danielson noted in the comments, this can never be null - you should check if o is null instead:
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}
if(getClass() != o.getClass()) {
return false;
}
Int other = (Int) o;
return toString().equals(other.toString()); // Here!
}
But in all fairness, there's no reason to use toString - you could just compare the internal val:
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}
if(getClass() != o.getClass()) {
return false;
}
Int other = (Int) o;
return val == other.val; // Here!
}
First when you override Methods please do it with #Override Annotation. Then i would implement your equals method in another way. Just do return this.val == other.val instead of doing this.toString() == other.toString(). Your toString() method implementation is ok. Your hashCode is good as well. But please remove that create method. Use a constructor instead.
Can I implement equals() method using eq() like this ?
public boolean equals(Object o) {
Value compare = (Value) o;
return eq(compare);
}
I'm trying to make a generic tuple class. It stores its elements as an ArrayList. Of course, this class should override hashcode and equals methods.
How could I make hashcode method for this class? You see, in the code, I am having trouble.
Also, for the equals method, why does the compiler force me to use the '?'. Why couldn't I just use the T?
public static class Tuple<T> {
ArrayList<T> tuple = new ArrayList<>();
public Tuple(ArrayList<T> items) {
for (T item : items) {
tuple.add(item);
}
}
#Override
public int hashCode() {
T sum = ???;
for (T item : tuple) {
sum += item.hashCode();
}
return sum;
}
#Override
public boolean equals(Object o) {
if (o instanceof Tuple<?>) {
Tuple<?> tup= (Tuple<?>) o;
if (tup.tuple.size() != this.tuple.size()) {
return false;
}
for (int i = 0; i < this.tuple.size(); i++) {
if (this.tuple.get(i) != tup.tuple.get(i)) {
return false;
}
}
return true;
} else {
return false;
}
}
}
As mentioned in the comments, we should delegate the hashCode and the equals methods to the ArrayList<T> tuple instance variable. For the hashCode it's trivial. For the equals it's just a little more complicated than that because we don't want our custom Tuple to be equals with an ArrayList. So here it is:
public class Tuple<T> {
// I made this private because I'm pedantric ;)
private final ArrayList<T> tuple = new ArrayList<>();
// this does the same as your code, it's just easier to read
public Tuple(ArrayList<T> items) {
tuple.addAll(items);
}
#Override
public int hashCode() {
return tuple.hashCode();
}
// generated by eclipse
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Tuple other = (Tuple) obj;
if (tuple == null) {
if (other.tuple != null)
return false;
} else if (!tuple.equals(other.tuple))
return false;
return true;
}
}
If you want to deal with the case when the tuple can be null, then you can use a slightly more complex hashCode:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((tuple == null) ? 0 : tuple.hashCode());
return tuple.hashCode();
}
In general, I don't like to write these methods myself. Usually, I make my IDE to generate the stuff. All I need to take care of is to re-generate it when I add new fields. Apache HashCodeBuilder and EqualsBuilder are also great alternatives.
I want to sort list of users on the basis of three criteria.
So i have created custom comparator to sort list but its not working as i want
public class CustomComparator implements Comparator {
List<Integer> user1Time = new ArrayList<>();
List<Integer> user2Time = new ArrayList<>();
int user1Count, user2Count;
ParseUser user1, user2;
Date user1Date, user2Date;
boolean user1Short, user2Short;
private String TAG="CustomComparator";
#Override
public int compare(Object lhs, Object rhs) {
user1 = (ParseUser) lhs;
user2 = (ParseUser) rhs;
user1Time = user1.getList("timeAvailable");
user2Time = user2.getList("timeAvailable");
//To compare Available time of both users with Searched Time
if(user1Time!=null){
user1Time.retainAll(Utils.availableTime);
user1Count = user1Time.size();
}else{
user1Count=0;
}
if(user2Time!=null){
user2Time.retainAll(Utils.availableTime);
user2Count = user2Time.size();
}else{
user2Count=0;
}
Log.d(TAG, "compare: "+user1.getString("name")+" "+user1Count);
Log.d(TAG, "compare: "+user2.getString("name")+" "+user2Count);
//To compare lastSeen of both the users
user1Date = user1.getDate("lastSeen");
user2Date = user2.getDate("lastSeen");
//To compare shortNotice avilablity of both the user
user1Short = user1.getBoolean("shortNotice");
user2Short = user2.getBoolean("shortNotice");
if(user2Time!= null && user2Time!= null && user1Date!= null && user2Date!= null){
if (user1Count>user2Count){
if(user1Short){
if(user1Date.compareTo(user2Date)>0){
return -1;
}else {
return -1;
}
}else if (user1Date.compareTo(user2Date)>0){
return -1;
}else if (user2Date.compareTo(user1Date)>0){
return 1;
}
}else if(user2Short){
if(user2Date.compareTo(user1Date)>0){
return 1;
}else {
return -1;
}
}else if (user2Date.compareTo(user1Date)>0){
return 1;
}else if (user1Date.compareTo(user2Date)>0){
return -1;
}
}
return 0;
}
}
but its not working properly
i want to sort list in three ways array of integers,boolean and date
as you can see in my code.
You could do something like this:
class Data {
int A;
int B;
int C;
public int getA() {
return A;
}
public void setA(int a) {
A = a;
}
public int getB() {
return B;
}
public void setB(int b) {
B = b;
}
public int getC() {
return C;
}
public void setC(int c) {
C = c;
}
}
class Sorter {
public void sort(List<Data> dataList){
Collections.sort(dataList,
Comparator.comparingInt(Data::getA)
.thenComparingInt(Data::getB)
.thenComparingInt(data->data.C)
);
}
}
here i use only comparingInt but you could do it with any kind of comparators.
I want specific object with all it's values by using it's unique id of object from object list.
I have tried but i am getting index -1 while running below code.
List<JobDataDetail> jobList = getJobList();
JobDataDetail object = jobList.get(jobList.indexOf(new JobDataDetail(jobReferenceId)));
from the class
public class JobDataDetail implements Serializable,Comparable<JobDataDetail> {
public int jobSequence;
public String jobReferenceId;
public String jobAddress;
public String jobScheduledDate;
public JobDataDetail() {
super();
// TODO Auto-generated constructor stub
}
public JobDataDetail(int jobSequence){
super();
this.jobSequence = jobSequence ;
}
public JobDataDetail(String jobReferenceId){
super();
this.jobReferenceId = jobReferenceId;
}
public int getJobSequence() {
return jobSequence;
}
public void setJobSequence(int jobSequence) {
this.jobSequence = jobSequence;
}
public String getJobReferenceId() {
return jobReferenceId;
}
public void setJobReferenceId(String jobReferenceId) {
this.jobReferenceId = jobReferenceId;
}
public String getJobAddress() {
return jobAddress;
}
public void setJobAddress(String jobAddress) {
this.jobAddress = jobAddress;
}
public String getJobScheduledDate() {
return jobScheduledDate;
}
public void setJobScheduledDate(String jobScheduledDate) {
this.jobScheduledDate = jobScheduledDate;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((jobReferenceId == null) ? 0 : jobReferenceId.hashCode());
result = prime * result + jobSequence;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
JobDataDetail other = (JobDataDetail) obj;
if (jobReferenceId == null) {
if (other.jobReferenceId != null)
return false;
} else if (!jobReferenceId.equals(other.jobReferenceId))
return false;
if (jobSequence != other.jobSequence)
return false;
return true;
}
#Override
public int compareTo(JobDataDetail another) {
return this.getJobReferenceId().compareTo(another.getJobReferenceId());
}
}
List.indexOf() uses equals() method to compare objects.
In your case, you are assuming that two objects with same jobReferenceId are equals but your equals() method doesn't say so (because of the jobSequence test at the end of your method).
If you want to get an item from your list by one of its attribute, the easiest way would be using filter expression in Java 8:
JobDataDetail job = jobList.stream()
.filter(j -> j.getAttribute().equals(someValue))
.findFirst();
If Java 8 is not an option, I would go for a classic for loop iterating over the list.
I have removed jobSequence condition check from equals method and it's working.
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)];