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...
Related
i am using Swing List control to bind data, I (must) use a class to make the model
public class SubjectListModel extends AbstractListModel<String> {
public ArrayList<Subject> listSubjects;
public SubjectListModel(ArrayList<Subject> listSubjects) {
this.listSubjects = listSubjects;
}
#Override
public int getSize() {
return listSubjects.size();
}
#Override
public String getElementAt(int index) {
return listSubjects.get(index).name;
}
class Subject{
int id;
string name;
}
I wish to use the List to bind my ArrayList, Can I set something like "display text field" for "name" field, and "value field" for my "id"? So that I can retrieve those values as needed.
The best dream is I can retrieve whole the selected "Subject" instead of a string field.
I seen the list only have getSelectedValue, and if I want to display the subject in the List, I must set getValueAt() in model to return the "name", and getSelectedValue() return the selected "name" too :( If I change getElementAt() in model class to return "Subject", the list will display #object.abxdef
Just override toString() of Subject, and return what ever you want to be displayed in the list. Then add all your Subject instances to the list. No need for a custom ListModel. Just use a DefaultListModel. When you get the selected Subject just use one of it's getters to the field you want.
Also no need to store your object in two locations, (i.e. the ListModel and the ArrayList) just add everything to the model.
class Subject {
private int id;
private String name;
public Subject(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() { return id; }
public String getName() { return name; }
#Override
public String toString() {
return name;
}
}
DefaultListModel model = new DefaultListModel();
model.addElement(new Subject(1, "Math"));
Subject subject = (Subject)model.getElementAt(0);
System.out.println(subject);
// result -> Math
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).
I ran into following situation and I am wondering about best solution. Let's say I have List<Object1> and List<Object2>, these lists are result of two separated queries. Both of them have the same size and there is relationship 1:1 between elements in the lists based on ID. I know that best solution would be fetching data in one DB query but that's possible right now.
So my question is, what is the best way to join these lists into let's say List<Object3>?
I would
convert the first list into Map with key as the ID and value as Object1.
iterate through the second list, get the object1 corresponding to the ID of object2.
perform the merge operation or whatever is intended and prepare object3 and put it in a list.
The resultant order would be that of in second list.
Make sure the queries order by id and then just iterate over the lists at the same time, whilst creating your new super list. This isn't foolproof, if the queries return differing sets of ids then the data will be corrupt. You could always add a check to make sure the ids match before adding the two objects to the super list though.
Use Apache Common BeanUtils as you don't have to write much code, also datatype convertions will be proper.
In this case both object1List and object2List should be in same order based on ID. To have that use Comparable interface to sort these based on ID for both Object1 and Object2
Example Code
Object1.java
public class Object1 implements Comparable<Object1>{
private Integer id;
private String name;
private int quantity;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public int compareTo(Object1 compareObject1) {
int compareId = ((Object1) compareObject1).getId();
//ascending order
return this.id - compareId;
}
}
Object2.java
public class Object2 implements Comparable<Object2>{
private Integer id;
private double amount ;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
public int compareTo(Object2 compareObject2) {
int compareId = ((Object2) compareObject2).getId();
//ascending order
return this.id - compareId;
}
}
Object3.java which will have fields names same as Object1 and Object2.java
Actual Implementation
int cnt = 0;
List<Object3> object3List = new ArrayList<Object3>();
List<Object1> object1List = Collections.sort(object1List);
List<Object2> object2List = Collections.sort(object2List);
for(Object1 obj1 : object1List) {
BeanUtils.copyProperties(obj3, obj1);
Object2 obj2 = object2List.get(cnt);
BeanUtils.copyProperties(obj3, obj2);
object3List.add(obj3);
cnt ++;
}
I would use a BidiMap (see Apache Commons Collections).
Moreover, if you're sure the two lists have the same size and each id is present within the two lists, you could sort the list by the id and go through them with a classic for loop.
Comparator<YourObject> comparator = new Comparator<YourObject>() {
#Override
public int compare(YourObject o1, YourObject o2) {
return o1.getId().compareTo(o2.getId());
}
};
Collections.sort(list1, comparator);
Collections.sort(list2, comparator);
// import org.apache.commons.collections.BidiMap;
// import org.apache.commons.collections.bidimap.DualHashBidiMap;
BidiMap map = new DualHashBidiMap();
// required: list1.size() == list2.size()
for (int i = 0; i < list1.size(); i++) {
map.put(list1.get(i), list2.get(i));
}
If equals and hashCode are using the ID, and they should if this represents the uniqueness in your objects, you could also use sets instead of lists. This way you will be able to do something like set1.addAll(set2)
I am new to jtree. I want to get the unique id or value of individual nodes which have same parent.
I tried with valuechanged() method, but i am able to get only the string value of every node.
I want to compare the current selecting node with some unique value of particular node. How can i achieve this?
I think i am making clear.
Is there any possibilites available?
Thanks in advance..
TreeNode has a getParent() method, you can compare the object reference returned with it with ==.
If you really need an unique id based on object identity, consider System.identityHashCode. See the following question:
How do you get the "object reference" of an object in java when toString() and hashCode() have been overridden?
I have been working on setting a unique Id for the DefaultMutableTreeNode. One method is to create a simple CustomUserObject Class which has tow properties, Id and Title. We can then assign the CustomUserObject instance as the Node UserObject property.
To make sure that only the Title is displayed in the Tree structure, override the toString() method in the CustomUserObject Class.
/* CustomUserObjectClass */
public class CustomUserObject implements Serializable {
private int Id = 0;
private String Title = null;
public CustomUserObject(int id, String title) {
this.Id = id;
this.Title = title;
}
public CustomUserObject() {
}
public int getId() {
return this.Id;
}
public String getTitle() {
return this.Title;
}
public void setId(int id) {
this.Id = id;
}
public void setSutTitle(String title) {
this.sutTitle = title;
}
#Override
public String toString() {
return this.Title;
}
Now to create a new node:
CustomUserObject uObj = new CustomUserObject(1, "My First Node");
DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(uObj);
uObj = childNode.getUserObject();
uObj.getId();
uObj.getTitle();
i have a java class like this
public class A {
private String field1;
private String field2;
// getters, setters but no equals and hashcode
}
and a list of objects of this class, i want to remove from this list all the duplicates elements that has the same field1 or the same field2, so i have 2 Comparators
public class Comparator1 implements Comparator<A> {
public int compare(A o1, A o2) {
return o1.getField1().compareToIgnoreCase( o2.getField1() );
}
}
public class Comparator2 implements Comparator<A> {
public int compare(A o1, A o2) {
return o1.getField2().compareToIgnoreCase(o2.getField2());
}
}
so to do the task i use treeset like
TreeSet<A> ts1 = new TreeSet<A>(new Comparator1())
ts1.addAll(list)
TreeSet<A> ts2 = new TreeSet<A>(new Comparator2())
ts2.addAll(ts1)
list.clear()
list.addAll(ts2)
but how can i do the same using just one comparator and one treeset ?
Thanks for the help
Update:
Thanks all for the answers, but after reading them i don't know if this is the right approach to the real problem.
In my real case field1 is like a phone number and field2 is like a name.
So i don't want to call the same phone number more than one time (this is the first treeset to removes duplicates) and i don't want to call more than one time the same name (the second treeset to removes duplicates)
You can modify the class but i'd like to know if this approach is ok to resolve the real problem.
If this approach is correct, from your question, i see that without modifying the class is not possible to use just one comparator
Thanks
You can't use one comparator to sort by two criteria at the same time, so there is no real way to go better than two TreeSets in your case. Of course, you can wrap them in one data structure.
(Alternatively you could use two HashMaps, each having one of the strings as key - this will be faster on average, but is more complicated to program.)
You can't, and it's not clear to me that what you're trying to do is well-defined.
Are you aware that your current approach depends both on the order in which elements are added and on whether you check field1 or field2 first for duplicates? Imagine you had these objects of class A:
A ab = new A("a", "b");
A cb = new A("c", "b");
A cd = new A("c", "d");
Checking field1 first gives the result [ab] or [ab, cd], depending on the order added.
Checking field2 first gives the result [cb] or [ab, cd], depending on the order added.
This is pretty strange behavior. Is this what you intended? I don't think it is possible to reproduce this with a single TreeSet and Comparator in the general case.
public static <A extends Comparable<?>> TreeSet<A> getTreeSet(Collection<A> list){
TreeSet<A> result = new TreeSet<A>();
HashSet<A> unique = new HashSet<A>();
unique.addAll(list);
result.addAll(unique);
return result;
}
Generic function that adds items to hashset to make them unique, and then drop them to TreeSet to sort. You can use it with: TreeSet<A> ts1 = getTreeSet(list);.
This approach works well for a fixed list.
#BalusC No, this assumes
public class A implements Comparable<A> {
private String field1;
private String field2;
#Override
public int compareTo(A o) {
// No null checks, because it's illegal anyways.
int tmp = 0;
if ((tmp = field1.compareToIgnoreCase(o.field1)) != 0)
return tmp;
if ((tmp = field2.compareToIgnoreCase(o.field2)) != 0)
return tmp;
return tmp;
}
// getters, setters but no equals and hashcode
}
If your intention is to do two levels of sorting(first: PhoneNumber and second:Name), then you can use the following code, where the duplicate check will be done against both the fields(field1 and field2). As we are already using compareTo for both the fields, it is not required to use equals and hashcode. But it is always good practice to use hashcode and equals.
public class A implements Comparable<A> {
private String field1;
private String field2;
public A(String number, String name) {
this.field1 = number;
this.field2 = name;
}
// First level sorting will be done by field1.
// If field1 is equal then second level sorting will be done on field2
#Override
public int compareTo(A o) {
int compareTo = field1.compareTo(o.getNumber());
if(compareTo==0){
return field2.compareTo(o.getName());
}
return compareTo;
}
public String getNumber() {
return field1;
}
public String getName() {
return field2;
}
}
public class RemoveDuplicate {
public static void main(String[] args) {
final ArrayList<Student> students = new ArrayList<Student>();
Set<Student> set = new TreeSet<Student>();
Student[] starr = new Student[6];
starr[0] = new Student("Student1", "1005");
starr[1] = new Student("Student2", "1004");
starr[2] = new Student("Student3", "1003");
starr[3] = new Student("Student6", "1002");
starr[4] = new Student("Student5", "1001");
starr[5] = new Student("Student6", "1000");
Arrays.sort(starr, Student.StudentIdComparator);
for (Student s : starr) {
students.add(s);
}
System.out.println(students);
set.addAll(students);
System.out.println("\n***** After removing duplicates *******\n");
final ArrayList<Student> newList = new ArrayList<Student>(set);
/** Printing original list **/
System.out.println(newList);
}}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Set;
import java.util.TreeSet;
import java.util.Comparator;
import java.util.List;
public class RemoveDuplicate {
public static void main(String[] args) {
Set<Student> set = new TreeSet<Student>();
List<Student> students = Arrays.asList(new Student("Student1", "1005"), new Student("Student2", "1004"),
new Student("Student3", "1003"), new Student("Student6", "1002"), new Student("Student5", "1001"),
new Student("Student6", "1000"));
// Sorting Using Lambda
students.sort(new Comparator<Student>() {
#Override
public int compare(Student s1, Student s2) {
return s1.getId().compareTo(s2.getId());
}
});
System.out.println(students);
set.addAll(students);
System.out.println("\n***** After removing duplicates *******\n");
final ArrayList<Student> newList = new ArrayList<Student>(set);
/** Printing original list **/
System.out.println(newList);
}
}
class Student implements Comparable<Student> {
private String name;
private String id;
public Student(String name, String id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#Override
public String toString() {
return "\n" + "Name=" + name + " Id=" + id;
}
#Override
public int compareTo(Student o1) {
if (o1.getName().equalsIgnoreCase(this.name)) {
return 0;
}
return 1;
}
// public static Comparator<Student> StudentIdComparator = (Student
// s1,Student s2) -> s1.getId().compareTo(s2.getId());
}