I have an application which is using Drools Expert to evaluate some rules. The results will be of this type:
String, String, Integer
A typical result example is:
"Rule 1", "RED", 1
"Rule 2", "AMBER", 2
"Rule 3", "GREEN", 1
"Rule 4", "INFO", 3
The first element is a key. So I am thinking of using a Map structure. The last field is an integer specified via an enum. I want to be able to pick from this list of results the rule with the maximum priority (which is the last field).
What is the best way to structure this in terms of using the Java collections library? Is the Map the best?
I want to be able to pick from this list of results the rule with the maximum priority (which is the last field).
You could package the data into a class that is comparable based on the last field, and then use a PriorityQueue.
class Data implements Comparable<Data> {
private String rule;
private String other;
private int priority;
...
#Override
public int compareTo(Data other) {
return Integer.compare(priority, other.priority);
}
}
Now, you can use a PriorityQueue<Data>.
Queue<Result> resultList = new PriorityQueue<Result>();
public class Result implements Comparable<Result>{
private String ruleText;
private String text; // 2. value
private int priority;
#Override
public int compareTo(Result result) {
return new Integer(priority).compareTo(result.getPriority());
}
public String getRuleText() {
return ruleText;
}
public void setRuleText(String ruleText) {
this.ruleText = ruleText;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
}
Yes Map are the best to store if you have something termed as key in your data collection. For prioritization, its best to use PriorityQueue.
The best way would be to create an Object implementing comparable.
class Rule implements Comparable<Rule>{
String firstPart;
String secondPart;
int priority;
//constructor
//getters and setters
#Override
public int compareTo(Rule other){
return Integer.compare(this.priority, other.priority);
}
}
Then you just put them all in a TreeSet<Rule> and iterate on it, they will come out sorted. Or you can store them in list and call Collections.sort(list).
Related
I see that simple enums can be created by these ways
public enum MyEnum1 {
FOO,
BAR;
}
public enum MyEnum2 {
FOO("FOO"),
BAR("BAR");
private final String value;
private MyEnum2(String value) {
this.value = value;
}
public String value() {
return value;
}
}
In the first case I can use MyEnum1.FOO.name() whereas in the second I can use MyEnum2.FOO.value() to serve my purpose. I want to know what is the best approach when I just want the enums to represent some constant set of Strings.
What are the pros/cons of using the above enums? Which should be preferred in which scenarios? Is there any drawback of using the name() method?
First solution will work for you. Second solution if you want extra info added to the enum:
public enum MyEnum2 {
FOO("This is the first", 867),
BAR("This is the second", 885);
private final String description;
private final Integer weight;
private MyEnum2(String description, Integer weight) {
this.description = description;
this.weight = weight
}
public String getDescription() {
return description;
}
public Integer getWeight() {
return weight;
}
}
I'd say that depends on the use case. I agree with Jeremy, that 1st approach looks better and is cleaner. However, if some other code depends on the enum name, than I'd use 2nd approach, since in the 1st one, refactoring the enum will break your app. But if you only want to print the name somewhere, then use the 1st one.
I have a set of objects of type "Part" and each Part is associated with quantity(a field that specifies number of units required of that particular Part ). Is there in way in java to store this data, other than hash map?
You can write a wrapper object that has two fields, Part and quantity:
public class PartWithQuantity
{
private Part part;
private int quantity;
public int getQuantity() { return quantity; }
public void setQuantity(int q) { quantity = q; }
public Part getPart() { return part; }
public void setPart(Part p) { part = p; }
}
You can also use a TreeMap if the concern is that the HashMap might use too much memory.
This can be done very easily by just storing the metadata into the arraylist.
You can take a class that contains one reference of part type and other(quantity) is int type. Then you can even store the instances of this new class into an arraylist. Do Remember ,you can access your information anytime from this arraylist by calling the object.
The simplest way to achieve this would be to modify the Part class and add the quantity field, along with its setter and getter.
Another option would be to use a wrapper object and store it in the Set.
I have created a convenience method called check() to easily identify the Part of interest:
public class PartExtended {
private Part part;
private int quantity;
public PartExtended(Part part, int quantity) {
this.part = part;
this.quantity = quantity;
}
public boolean check(Part part) {
return part.equals(this.part);
}
public Part getPart() {
return part;
}
public int getQuantity() {
return quantity;
}
}
To retrieve a Part's quantity, use a for loop:
Set<PartExtended> data = new HashSet<>();
data.add(new PartExtended(new Part(), 0));
for (PartExtended item : data) {
if (item.check(new Part())) {
int quantity = item.getQuantity();
}
}
I am trying to implement a solution (in Java 1.6) where i need to store some values (for a set of properties) and thinking in three options considering the following three (Any other idea is of course wellcome!)
Option 1
Create a class (call it Property) that can store different type of objects (String, int, boolean...) and and work with the set of properties as a List<Property>
Something like:
private String type; //Store the type of Object
private String name; //Store the name of the property
private String valueStr; //Store the String value
private int valueInt; //Store the int value
private boolean valueBool; //Store the boolean value
I dont really like the idea of having many properties and using only one of them. (only one of the values will be set per property)
Option 2
Use HashMap<String, Object> and parse the type on each case.
Have the good thing that you can get the Property by name
Option 3
Use HashMap<String, Property> Where the String is the name of the property and you can get the value with the name and no need to parse.
Questions are:
Which of one you think is the best one?
or if none of them are good i would like to hear other ideas
Also is there any performance difference between the List and the HashMap?
Thanks in advance for the help.
I think better is to have a custom Value class like this:
public class MyValue {
enum Type {
INT, STRING, BOOL;
}
private Type type; //Store the type of Object in Type Enum
private Object value; //Store the value in Object
public void setValue(int val) {
type = Type.INT;
value = new Integer(val);
}
public void setValue(String val) {
type = Type.STRING;
value = val;
}
public void setValue(boolean val) {
type = Type.BOOL;
value = new Boolean(val);
}
public String stringVal() {
// check type to be STRING first
return (String) value;
}
public int intVal() {
// check type to be INT first
return ((Integer) value.intValue());
}
public boolean booleanVal() {
// check type to be BOOL first
return ((Boolean) value.booleanValue());
}
}
You will need to convert from Object to specific type based on enum Type in your getters.
Another option would be something like this, using inheritance rather than keeping a large number of unused fields around.
public interface Property {
String getType();
String getName();
Object getValue();
}
public abstract class AbstractProperty implements Property {
private final String name;
protected AbstractProperty(String name) {
this.name = name;
}
}
public class StringProperty extends AbstractProperty {
private final String value;
public StringProperty(String name, String value) {
super(name);
this.value = value;
}
#Override
public String getType() {
return String.class.getName();
}
#Override
public String getValue() {
return value;
}
}
public class IntegerProperty extends AbstractProperty {
private final Integer value;
public IntegerProperty(String name, Integer value) {
super(name);
this.value = value;
}
#Override
public String getType() {
return Integer.TYPE.getName();
}
#Override
public Integer getValue() {
return value;
}
}
I think option 2 would be the best for you. Considering that you are storing properties I am expecting that you would be querying this list quite often which again points in the direction of a HashMap as that would make your lookup very efficient.
I suggest using an enum instead. Enums are good for holding lists of values, and are effective at retrieval.
public enum Property {
TYPE,
NAME,
VALUEINT; //...
private String sProp = "";
private int iProp = 0;
private boolean bProp = false;
public String getStringProp() {return sProp;}
public int getIntProp() {return iProp;}
public boolean getBoolProp() {return bProp;}
public void setStringProp(String str) {this.sProp = str;}
public void setIntProp(int i) {this.iProp = i;}
public void setBoolProp(boolean b) {this.bProp = b;}
}
This can then be accessed with Property.TYPE, Property.VALUEINT, etc. You can set properties with Property.TYPE.setStringProp(), and get them with Property.TYPE.getStringProp().
You can read more about enums from Oracle's site.
I am unsure if there's one 'best' way. It really depends on how the data would be used after storing in a data structure.
In cases when I just need to accumulate properties and do something on each of them, I'd use a list, or even an array, sometimes.
If you might have to get a particular property, say by name, then a HashMap could help.
Again if you want to use the native object type or an instance of Property depends on what kind of data you have.
Which performs better depends on the number of objects you have, how you'd access them for use, how often you'd insert and several other factors.
I have a list of java beans, now I want to sort them with specified property and sort order
(the property and sort order are input parameters), like this:
class Person{
private String userName;
private Integer age;
private String address;
public void sort(List<Person> ps, String property, String sortOrder)
{
// How to use the property and sortOrder??
Collections.sort(ps);
}
}
What is the best way of writing the sortList() method?
actually I have one way to do this. I can write two static properties for Person. then I set these two properties before sorting:
class Person implements Comparable<Person>{
private String userName;
private Integer age;
private String address;
public static String sortProperty;
public static String sortOrder;
public void sort(List<Person> ps, String property, String sortOrder)
{
Person.sortProperty=property;
Person.sortOrder=sortOrder;
Collections.sort(ps);
}
#Override
public int compareTo(Person o)
{
// find the property with Person.sortProperty using reflection
// then sort the property
}
}
This is not a good solution. Could anyone give me some suggestion? thanks in advance
Hope this makes sense for you. Use final keyword to avoid creating static variable for passing sort order. Also changed it to boolean for easy access. Below code is just for illustration.
public static void sort(List<Person> ps, String property, final boolean asc) {
if (property.equals("userName")) {
Collections.sort(ps, new Comparator<Person>() {
public int compare(Person o1, Person o2) {
// pls use appropriate compareTo I always get confused
// which one to call when it is asc or desc.
if (asc)
return o1.getUserName().compareTo(o2.getUserName());
else
return o2.getUserName().compareTo(o1.getUserName());
}
});
}
if (property.equals("age")) {
Collections.sort(ps, new Comparator<Person>() {
public int compare(Person o1, Person o2) {
if (asc)
return o1.getAge().compareTo(o2.getAge());
else
return o2.getAge().compareTo(o1.getAge());
}
});
}
}
You can implement a Comparator and use it like this.
Collections.sort(ps, myComparator)
Inside the comparator you can just retrieve property and sortOrder from person and compare with these variable
Collections.sort(ps, new Comparator<Person>() {
#Override
public int compare(Person p1, Person p2) {
int result = 0;
if(sortProperty.equals("userName")) {
result = p1.userName.compareTo(p2.userName);
} else if(//...
//determine how based on sortOrder here
//e.g.
if(sortOrder.equals("ascending") {
return result;
} else {
return (result * (-1));
}
}
});
Note: property and sortOrder need to be declared final.
You should be able to use the Bean Comparator for this.
Write three Comparators. They could be static fields. E.g.
public static final Comparator COMPARE_BY_NAME = (your code here)
And similar for COMPARE_BY_AGE etc.
Pass them to the standard Java sort() methods.
To make the sorting as generic extended method of a list you can use below code:
public static List<T> SortList<T>(this List<T> list, string sortDirection, string sortExpression)
{
if (sortDirection.ToLower() == "sorting_asc")
{
return (from n in list
orderby GetDynamicSortProperty(n, sortExpression) ascending
select n
).ToList();
}
else if (sortDirection.ToLower() == "sorting_desc")
{
return (from n in list
orderby GetDynamicSortProperty(n, sortExpression) descending
select n
).ToList();
}
else
{
return list;
}
}
public static object GetDynamicSortProperty(object item, string propName)
{
//Use reflection to get order type
return item.GetType().GetProperty(propName).GetValue(item, null);
}
Calling:
List<Employee> employees = new List<Employee>();
var sortedEmployees = employees.SortList(sortedorder, sortedcolumn);
I am storing objects in ArrayList, where my pojo is as
public class POJOSortableContacts {
private Long id;
private String displayName;
public POJOSortableContacts(Long id, String displayName) {
super();
this.id = id;
this.displayName = displayName;
}
//Setter and Getters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
//This will be used to sectioned header.
public String getLabel() {
return Character.toString(displayName.charAt(0)).toUpperCase();
}
//Sortable categories
//Sort by Contact name
public static Comparator<POJOSortableContacts> COMPARE_BY_NAME = new Comparator<POJOSortableContacts>() {
public int compare(POJOSortableContacts one, POJOSortableContacts other) {
return one.getDisplayName().compareToIgnoreCase(other.getDisplayName());
//return s1.toLowerCase().compareTo(s2.toLowerCase()); //it returns lower_case word first and then upper_case
}
};
//Sort by id
public static Comparator<POJOSortableContacts> COMPARE_BY_ID = new Comparator<POJOSortableContacts>() {
public int compare(POJOSortableContacts one, POJOSortableContacts other) {
return one.id.compareTo(other.id);
}
};
}
and Arraylist structure is as
ArrayList<POJOSortableContacts> contactArrayList = new ArrayList<POJOSortableContacts>()
, I want to search an object from contactArrayList by id (for example I want an object which id is 20), I want to use binarysearch for this. So how can it will be?
You can use
POJOSortableContacts contact = Collections.binarySearch(contactArrayList,
new POJOSortableContacts(20, ""),
COMPARE_BY_ID);
The new POJOSortableContacts is just a dummy object to act as the key.
Of course, this will only work if your list is sorted by ID to start with - you can't use a binary search on an unsorted list (or on a list which is sorted in a different way).
I will rather suggest that you use a HashMap.
Map<Long,POJOSortableContacts> contactMap = new HashMap<Long,POJOSortableContacts>();
Fill up your contactMap like this:
contactMap.put(myContact.getId(), myContact);
Searching then becomes trivial:
POJOSortableContacts myContact = contactMap.get(myID);
To be able to use binary search, your collection must be sorted. You could sort your ArrayList each time before your search, but that would negate the advantage of using binary search (you could just do a linear search over the unsorted list and still be faster).
ArrayList has a method - BinarySearch, which takes object to search as a parameter.
POJOSortableContacts contactToSearch = new POJOSortableContacts(someId, "Name");
POJOSortableContacts myContact = contactArrayList.BinarySearch(contactToSearch);
Hope this helps.
Sidestepping the question a bit, if you can't have duplicates in the list you'd likely be better served by using a SortedSet to store the contacts. No sorting before using binarySearch anymore...