Inline Object Comparison Java - java

I am trying to sort an arraylist with the following method. I want US to be first, followed by UK, etc. However this doesn't seem to be doing anything. What am I doing wrong?
orderedTerritories.sort((o1, o2) -> {
if (o1.getCode().equals("US*"))
return 1;
else if (o2.getCode().equals("US*"))
return 0;
else if (o1.getCode().contains("UK") && o1.getContains() != null)
return 1;
else if (o2.getCode().contains("UK") && o2.getContains() != null)
return 0;
else if (o1.getCode().equals("DE*"))
return 1;
else if (o2.getCode().equals("DE*"))
return 0;
else if (o1.getCode().equals("JP"))
return 1;
else if (o2.getCode().equals("JP"))
return 0;
else if (o1.getCode().equals("IN"))
return 1;
else if (o2.getCode().equals("IN"))
return 0;
else return 1;
});

Your sorting logic dose not check if both code's are same and also returns 0 instead of negative value when o1.getCode() is less than o2.getCode() . Without doing it you are breaking comparator contract.
Based on your sorting logic you can't simply rely on country code's string representation for sorting. To mitigate it you need to define a custom ordering value to each country. I am assuming that you can't modify the get code method to return Enum or some custom object. In that case you can define a map between country code and order and use that order value for sorting. Here is an example:
One of comments already is suggesting similar approach.
private static Map<String, Interger> codeToOrderMap = new HashMap<>();
static{
codeToOrderMap.put("US*", 0);
codeToOrderMap.put("UK", 1);
codeToOrderMap.put("DE*", 2);
codeToOrderMap.put("JP", 3);
codeToOrderMap.put("IN", 4);
}
orderedTerritories.sort((o1, o2) ->
codeToOrderMap.get( o1.getCode() ).compareTo( codeToOrderMap.get( o2.getCode() );
Without using above approach or custom code you will have to write a very long messy comparator.

I tend to agree with Lew Bloch in that you should use a more object oriented approach by using an enum.
I don't understand your response to the comment that Lew Bloch posted. You said, "Can't since I cant hard code it in. Is there no way to do simple ordering in java?" but you're already hardcoding the values in your current code. For example you have things like this in your code:
o1.getCode().equals("US*") In this statement the "US*" is hardcoded.
Here is an example of the enum approach using just US and UK codes:
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
public class Example implements Comparable<Example>
{
public enum CountryCode{
US,UK
}
public static void main(String[] args)
{
List<Example> codeList = new ArrayList<>();
codeList.add(new Example(CountryCode.UK));
codeList.add(new Example(CountryCode.US));
System.out.println("Before sort: "+codeList);
Collections.sort(codeList);
System.out.println("After sort: "+codeList);
}
private CountryCode countryCode;
public Example(CountryCode code){
this.countryCode = code;
}
public CountryCode getCountryCode(){
return countryCode;
}
public int compareTo(Example other){
return this.countryCode.compareTo(other.getCountryCode());
}
public String toString(){
return "Example: "+countryCode.toString();
}
}
Since the enum contains US and UK in that order and the Example class defers to the enum for its implementation of compareTo the List of Example is sorted such that Example objects whose country code is US come before those with a country code of UK.
OUTPUT:
Before sort: [Example: UK, Example: US]
After sort: [Example: US, Example: UK]
Final Items: I'm not clear what the "*" is meant to represent in your code values. If there are requirements that you have not specified then this approach may not work as intended.

Thank you, I factored in what you guys said to the following solution, which works:
List<Territory> orderedTerritories = new LinkedList<>();
List<Integer> integerValues = new ArrayList<>();
Map<Integer, Territory> intToTerritoryMap = new HashMap<>();
int i = 5;
for (Territory territory : finalSet) {
int index = 5;
if (territory.getCode().equals("US*"))
index = 0;
else if (territory.getCode().contains("UK") && territory.getContains() != null)
index = 1;
else if (territory.getCode().equals("DE*"))
index = 2;
else if (territory.getCode().equals("JP"))
index = 3;
else if (territory.getCode().equals("IN"))
index = 4;
if (index < 5) {
intToTerritoryMap.put(index, territory);
integerValues.add(index);
} else {
intToTerritoryMap.put(i, territory);
integerValues.add(i++);
}
}
Collections.sort(integerValues);
integerValues.forEach(j -> {
orderedTerritories.add(intToTerritoryMap.get(j));
});
return orderedTerritories;
Which is verbose and hard codes in numbers. I wish there was a simpler way.

Related

Sort Array list of objects based on object attributes

I have list which contains a property class object, In the list i have 3 status
not_paid
paid
part_paid
I want to sort my list below mentioned order.
First - not_paid
second- part_paid
third -paid
How can I sort my list using Comparator class.?
public static Comparator<OrderHistoryItemData> COMPARE_BY_PAYMENT = new Comparator<OrderHistoryItemData>() {
public int compare(OrderHistoryItemData one, OrderHistoryItemData other) {
String p1 = one.getAttributes().getFieldPaymentStatus();
String p2 = other.getAttributes().getFieldPaymentStatus();
if (p1.equals(p2)) {
return 0;
}
if (p1.equals("not_paid") && (p2.equals("part_paid") || p2.equals("not_paid"))) {
return -1;
}
if (p1.equals("not_paid") && p2.equals("not_paid")) {
return -1;
}
return 1;
}
};
This is my Code. i am getting below order using this code.
paid-->not_paid-->part_paid
This is my Update Code. I got my result.
public static Comparator<OrderHistoryItemData> COMPARE_BY_PAYMENT = new Comparator<OrderHistoryItemData>() {
public int compare(OrderHistoryItemData one, OrderHistoryItemData other) {
String p1 = one.getAttributes().getFieldPaymentStatus();
String p2 = other.getAttributes().getFieldPaymentStatus();
if (p1.equals(p2)) {
return 0;
}
if (p1.equals("not_paid") && (p2.equals("part_paid") || p2.equals("paid"))) {
return -1;
}
if (p1.equals("part_paid") && p2.equals("paid")) {
return -1;
}
return 1;
}
};
To avoid complex comparator, I encourage you to export your statuses to an enum. (Plus this will work if you will add more statuses in the future, without the need to change logic in your comparator):
enum PaymentStatus { // Write them in order you want to be sorted
NOT_PAID,
PART_PAID,
PAID
}
Then sorting will be as simple as :
list.sort(Comparator.comparing(item ->item.getAttributes().getFieldPaymentStatus()));
What you can do is first mapping the strings to integers in the desired order, and then simply subtracting them from eachother.
private static Comparator<Payments> comparator = new Comparator<Payments>() {
// Use this mapping function to map the statuses to ints.
// The lowest number comes first
private int map(String str) {
switch (str) {
case "not_paid":
return 0;
case "part_paid":
return 1;
case "paid":
return 2;
default:
return 3;
}
}
// Alternatively, you can use the Map interface to define the sorting
// order.
#Override
public int compare(Payments o1, Payments o2) {
return map(o1.status) - map(o2.status);
}
};
I suggest – Schidu Luca already mentioned it in his answer – that you use enums to define a fixed set of known values, like payment statuses. This provides compile-time safety.
Note: I wouldn't, however, suggest to bind the enum declaration order to the sorting order.

How good or bad is it to iterate over a hash-table after checking that it contains a value you want to remove?

I'm currently practicing Algorithm design on HackerRank.
This question pertains to the challenge found here:
https://www.hackerrank.com/challenges/ctci-ransom-note
I solved this problem fairly quickly. However, I ran into an issue that kind of bugs me. I can check for a value on my hash table by using the contains(value) function. However, I didn't see any way to retrieve the key/keys associated with it. In order to do this I was forced to iterate through the table until I found that value again.
While I see the usefulness of Hash Tables... I don't think I am going about solving the problem in an optimal way. I feel like it's a time waster to iterate through the table if I already know it contains the value I want to remove.
One idea I had was to make two tables and have them be the "mirrored" version of one another, as in the original map is using the numbers as keys and the copy or mirrored map uses the keys as the values. However, this seems impractical and I have a feeling that I'm just missing something essential in my knowledge of Hash functions or something.
One reason I'm thinking about this is that I recently made a program that uses a sqlight table to hold data. I only need one loop to search for and delete these values, which makes it more efficient doesn't it?
Could I please get an explanation of how to better achieve what my code below does?
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
public class Solution {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int m = in .nextInt();
int n = in .nextInt();
String isTrue = "Yes";
Hashtable myTable = new Hashtable();
String magazine[] = new String[m];
for (int magazine_i = 0; magazine_i < m; magazine_i++) {
myTable.put(magazine_i, in .next());
}
Set < Integer > keySet = myTable.keySet();
for (int ransom_i = 0; ransom_i < n; ransom_i++) {
String temp = in .next();
//System.out.println("Line " + ransom_i);
if (!myTable.containsValue(temp)) {
isTrue = "No";
break;
} else {
for (int key: keySet) {
if (myTable.get(key).equals(temp)) {
myTable.remove(key);
//System.out.println("Found it");
break;
}
}
}
}
System.out.println(isTrue);
}
}
Here's an easy way to do it:
public class DenyReturn<K,T> extends Map<K,T>{
private Map m;
private List<T> dontreturn;
public DenyReturn(Map<K,T> m, List<T> dontreturn) {
this.m = m;
this.dontreturn = dontreturn;
}
public T get(Object key) {
T val = super.get(key);
if (dontreturn.contains(val)) return null;
return val;
}
//implement all other methods of Map by invoking the inner map methods
}

Sorting an object array based on a property

EDIT: Added some information.
I got an array of Objects. Each object has a name and a value. I need to sort the objects in descending order of those values, and print the names. I saw this easy solution but can't seem to apply it to my problem: http://www.mkyong.com/java/java-object-sorting-example-comparable-and-comparator/
The code compiles with no error but the array is not sorted at all. I know this because I know what the output should be i.e. the output should be something like var364, var200, var65 etc. and what i get is var1, var2, var3 etc.
I tried to strip the code of the irrelevant parts here:
Main class
print(data.preselection());
private void print (UnitRow preselectedUnitRow) {
out.printf("Variables after preselection: \n");
for (int i=0;i<PRESELECTION_LIMIT;i++) {
out.printf("%s, ",preselectedUnitRow.getUnitName(i));
}
}
Dataset (data)
private UnitRow data;
...
public UnitRow preselection() {
UnitRow standardDeviationUnits = new UnitRow(numberOfVariables);
for (int i=0;i<numberOfVariables;i++){
Unit unit = new Unit(1,variableNames[i],calculateStandardDeviation(i));
standardDeviationUnits.add(unit);
}
standardDeviationUnits.sort();
return standardDeviationUnits;
}
UnitRow
import java.util.Arrays;
public class UnitRow {
private Unit[] units;
private int count;
...
public void sort() {
Arrays.sort(units);
}
}
Unit
public class Unit implements Comparable<Unit>{
private NumberRow elements; //just a class with an array of doubles
private String name;
...
#Override
public int compareTo(Unit compareUnit) { //getValue returns a single type double number
int comparison = (int) (compareUnit.getValue(0) - getValue(0));
return comparison;
}
}
I am assuming my implementation of Comparable is wrong. Can you spot the problem?
I say this because I tested as following:
System.out.println(standardDeviationUnits.getValue(0,0));
standardDeviationUnits.sort();
System.out.println(standardDeviationUnits.getValue(0,0));
And the exact same value is returned.
It looks like reverse order
public int compareTo(Unit compareUnit) {
if (getValue(0) < compareUnit.getValue(0)) return 1;
else if (getValue(0) > compareUnit.getValue(0)) return -1;
return 0;
}
Try this.
Also note that in your compareTo, you unnecessarily wrote return 2; and wrote 3 if instead of 1 if-else.
If you are trying to sort as per names:
return compareUnit.name.compareTo(name);
else I have no idea what attribute your getValue(0) returns to you but still if you are trying to sort as per getValue(0):
return compareUnit.getValue(0)-getValue(0);

Looking to associate strings to ints in a cleaner/more efficient way

How can I improve this?
The relationship is one to one and continuous on [-1,5] so i was thinking of using enum, but I'm not sure how to compare a string value to an enum value.
If there is any better way to do this, please suggest.
Thanks!
private int evaluateWord(String sval) {
if (sval.equals("program"))
return 1;
else if (sval.equals("begin"))
return 2;
else if (sval.equals("end"))
return 3;
else if (sval.equals("int"))
return 4;
else if (sval.equals("if"))
return 5;
else
System.exit(0);
Have you considered stuffing the mapping into a HashMap once, and then just querying the map?
For example, something like this:
private static final Map<String,Integer> m_map = new HashMap<String,Integer>();
static {
m_map.put( "program", 1 );
m_map.put( "begin", 2 );
m_map.put( "end", 3 );
m_map.put( "int", 4 );
m_map.put( "if", 5 );
}
private int evaluateWord(String sval) {
Integer value = m_map.get( sval );
if ( null != value ) {
return value;
}
else {
System.exit(0);
}
}
By the way, it looks as if you're writing a parser. It can be reasonable to write a parser by hand. Another option to consider, unless you have a good reason to write it by hand, is a parser generator like ANTLR.
Using an enumeration:
enum Word {
PROGRAM(1,"program"),
BEGIN(2,"begin"),
END(3,"end"),
INT(4,"int"),
IF(5,"if");
private final int value;
private final String representation;
Word(int value, String representation)
{
this.value = value;
this.representation = representation;
}
public int value()
{ return value; }
private static Map<String, Word> fromRep =
new HashMap<String, EnumExample2.Word>();
public static Word fromRepresentation(String rep) {
if (!validRep(rep)) {
throw new IllegalArgumentException("No rep: "+rep);
}
return fromRep.get(rep);
}
public static boolean validRep(String rep)
{ return fromRep.get(rep) != null; }
static {
for (Word word : Word.values()) {
fromRep.put(word.representation, word);
}
}
}
Then your logic is:
private int evaluateWord(String sval) {
if (!Word.validRep(sval)) {
System.exit(0);
}
return Word.fromRepresentation(sval).value();
}
A hashmap could work:
private static HashMap<String, Integer> lookup = new HashMap<String, Integer>();
static {
lookup.put("program", 1);
lookup.put("being", 2);
lookup.put("end", 3);
lookup.put("int", 4);
lookup.put("if", 5);
}
private int evaluateWord(String sval) {
if ( lookup.containsKey(sval) ) {
return lookup.get(sval);
}
System.exit(0);
}
This is what a map is for;
Create a HashMap, add key and values to the map like
wordMap.put("program", Integer.valueOf(1));
....
then, to get the value do
Integer val = wordMap.get(sval);
Honestly, I wouldn't worry about keeping something like this ultra efficient, but there is a change you could make. If the word you pass is the last word you check for then your program ends up performing all of the checks in your function. This shouldn't be a problem in this case, but generally you don't want to flood your program with if statements, especially if you have a lot of cases.
Use a hashtable and just insert pairs. This way, all of your evaluateWord calls will return in amortized constant time. :)
Good luck!
Why do you need a (very subjective) "cleaner" way?
You could get more efficiency from using a hash lookup but you'd want to be certain it's called quite a bit to make the extra coding effort worthwhile. If it's something that happens infrequently (and, by that, I mean something like less than once a second), it's not worth doing (YAGNI).
One thing you might want to do for better looking code (if that's important) is to ditch the else bits, they're totally unnecessary:
private int evaluateWord(String sval) {
if (sval.equals("program")) return 1;
if (sval.equals("begin")) return 2;
if (sval.equals("end")) return 3;
if (sval.equals("int")) return 4;
if (sval.equals("if")) return 5;
System.exit(0);
}
You could just use an array or hashmap to map the enum values to the string values.
Inspired by your enum comment, I present the following. It's a bit hackish, but:
enum Word
{
PROGRAM (1), BEGIN (2), END (3), INT (4), IF (5);
public int value;
public Word (int value)
{
this.value = value;
}
};
int evaluateWord (String word)
{
return Word.valueOf(word.toUpperCase( )).value;
}
I love Java enums because you can do things like this. This is especially useful if you later want to (for example) add a unique behaviour for each word, or to maintain a long list of words. Note though that it is case insensitive.
Or, alternately:
enum Word
{
PROGRAM, BEGIN, END, INT, IF;
};
int evaluateWord (String word)
{
return Word.valueOf(word.toUpperCase( )).ordinal( ) + 1;
}

Java Convert Object[] Array to Vector

What's the best way to convert an Object array to a Vector?
JDE < 1.5
public Vector getListElements()
{
Vector myVector = this.elements;
return myVector;
}
this.elements is an Object[]
Thanks,
rAyt
I should clarify my question
My target platform is a blackberry.
Collections aren't supported. Array.asList() isn't, either :/
Full Class
package CustomElements;
import net.rim.device.api.ui.component .*;
import net.rim.device.api.collection.util.*;
import net.rim.device.api.util.*;
import java.util.*;
public class ContactsList extends SortedReadableList implements KeywordProvider
{
// Constructor
public ContactsList(Vector contacts)
{
super(new ContactsListComparatorByFirstName());
loadFrom(contacts.elements());
}
// Add Element to ContactsSortedReadableList
void addElement(Object element)
{
doAdd(element);
}
public Vector getListElements()
{
return new Vector(Collection
Vector test = this.getElements();
}
// getKeywords
public String[] getKeywords(Object element)
{
return StringUtilities.stringToWords(((Contact)element).get_contactFirstName());
// return StringUtilities.stringToWords(element.toString());
}
// Comparator sorting Contact objects by name
final static class ContactsListComparatorByFirstName implements Comparator
{
public int compare(Object o1, Object o2)
{
// Sticky Entries Implementation
if(((ContactsListObject)o2).getSticky())
{
return 1;
} else
if (((ContactsListObject)o1).getSticky())
{
return -1;
} else
{
if(((ContactsListObject)o1).get_contactFirstName().compareTo(((ContactsListObject)o2).get_contactFirstName()) <0)
{
return -1;
}
if(((ContactsListObject)o1).get_contactFirstName().compareTo(((ContactsListObject)o2).get_contactFirstName()) >0)
{
return 1;
}
else
{
return 0;
}
}
}
}
}
return new Vector(Arrays.asList(elements));
Now, it may look as if you are copying the data twice, but you aren't. You do get one small temporary object (a List from asList), but this provides a view of the array. Instead of copying it, read and write operations go through to the original array.
It is possible to extends Vector and poke its protected fields. This would give a relatively simple way of having the Vector become a view of the array, as Arrays.asList does. Alternatively, just copying data into the fields. For Java ME, this is about as good as it gets without writing the obvious loop. Untested code:
return new Vector(0) {{
this.elementData = (Object[])elements.clone();
this.elementCount = this.elementData.length;
}};
Of course, you are probably better off with a List than a Vector. 1.4 has completed its End of Service Life period. Even 1.5 has completed most of its EOSL period.
In J2ME, you're stuck iterating over the array and add the elements one by one.
Vector v = new Vector();
for (int i = 0; i < this.elements.length; i++) {
v.add(this.elements[i]);
}
A simplified comparator which does basically the same thing.
final static class ContactsListComparatorByFirstName implements Comparator {
public int compare(Object o1, Object o2) {
// Sticky Entries Implementation
ContactsListObject clo2 = (ContactsListObject) o2;
ContactsListObject clo1 = (ContactsListObject) o1;
if (clo2.getSticky()) return 1;
if (clo1.getSticky()) return -1;
return clo1.get_contactFirstName().compareTo(clo2.get_contactFirstName());
}
}
Using generics and ?: it would be just
static final class ContactsListComparatorByFirstName implements Comparator<ContactsListObject> {
public int compare(ContactsListObject clo1, ContactsListObject clo2) {
return clo2.getSticky() ? 1 : // Sticky Entries Implementation
clo1.getSticky() ? -1 :
clo1.get_contactFirstName().compareTo(clo2.get_contactFirstName());
}
}
But to answer your question... (oh I see Tom has what I would put already)
imho your only viable option is:
public Vector getListElements()
Vector vector = new Vector(this.elements.length);
for (int i = 0; i < this.elements.length; i++) {
vector.add(this.elements[i]);
}
return vector;
}
Copy the array elements to the Vector, or
Use Arrays.asList(...) to return a List, which isn't exactly a Vector, but you should be coding the List interface anyway.
A reasonably concise way to do it is something like:
Object[] xx = { 1, "cat", new Point(100,200) };
Vector vv = new Vector(Arrays.asList(xx));
System.out.println("vv=="+vv.toString());
But y'all knew that already, I guess.

Categories