I have a bubble sort function that orders LinkedList of SomeObj by "a" variable. What if i want to order the list by "b" variable at the same time? What can i do instead of writing another function with b?
public static void BubbleSort(LinkedList<SomeObj> objs) {
int len = objs.size();
for(int pass = 1; pass < len; pass++) {
for (int i=0; i < len - pass; i++) {
if(objs.get(i).a > objs.get(i + 1).a) {
SomeObj p = objs.get(i);
objs.set(i,objs.get(i+1));
objs.set(i + 1, p);
}
}
}
}
Implement Comparator interface in a class with its compare method.
that accepts two objects and compares them which returns -ve,0,+ve values to tell less than , equal or greater than.
create an object of this Comparator and pass it to bubble sort method and let it use its compare method to compare the two object.
Your object should have getters for all such fields.
Also whenever you wanna change the object's criteria for comparison , use a different Comparator.
Check this example.
You would have your SomeObj implement the Comparable interface and then have your sort interact with it using that interface.
If you can a good way to sort by first "a" then "b" is to implement Comparable in your SomeObj class and make a compareTo method that compares on both a and b. http://www.javapractices.com/topic/TopicAction.do?Id=10
Decide which has the highest priority. Check the higher priority variable - if they are different, just sort as if you are only sorting on that. If the high priority variable matches, then you have to go back to the lower priority one, and base your whole compare on that.
if (obj1.getA() != obj2.getA()) {
// do compare on As
// e.g. return onj2.getA() - obj1.getA()
}
else { // A's match, so do compares on B
// e.g. return obj2.getB() - obj1.getB()
}
I think the simplest way to do that is swap variable values rather than list items. Using this approach you can "sort" the list in different ways simultaneously.
I guess there is a kind of misunderstanding - it's not about sorting by a and then by b, it's a kind of 2 lists in one, and user wants to sort them both independently but without creating the second list, or am I not right?
For sorting List you can use
Collections.sort(List list, Comparator c));
like in this main method
class Pair{
int a;
int b;
public Pair(int a, int b) {
this.a=a;
this.b=b;
}
public String toString() {
// TODO Auto-generated method stub
return "["+a+","+b+"]";
}
//test
public static void main(String[] args) {
Comparator<Pair> comparatorA=new Comparator<Pair>() {
#Override
public int compare(Pair o1, Pair o2) {
if (o1.a>o2.a) return 1;
if (o1.a<o2.a) return -1;
return 0;
}
};
LinkedList<Pair> list=new LinkedList<>();
list.add(new Pair(1,2));
list.add(new Pair(2,1));
list.add(new Pair(3,1));
list.add(new Pair(1,3));
Collections.sort(list, comparatorA);
System.out.println(list);
}
}
Now you can just make comparator for b value and use Collections.sort with that comparator
Related
The goal here is to insert elements into a TreeSet where the ordering is done by a custom objects internal List.
public class CustomObject implements Comparable<CustomObject> {
List<Integer> innerObjectList = new ArrayList<>();
#Override
public boolean compareTo(CustomObject o) {
#compare natural ordering of elements in array.
}
}
This is what I'm currently doing, it works but I was hoping to find a native way to do it.
#Override
public int compareTo(#NotNull AisleMap o) {
if (o.aisles.size() > aisles.size())
return 1;
if (o.aisles.size() < aisles.size())
return -1;
for (int i = 0; i<aisles.size(); i++) {
int compare = o.aisles.get(i).compareTo(aisles.get(i));
if( compare != 0) {
return compare;
}
}
return 0;
}
I'm trying to figure out how to do something like o.innerObjectList.compare(toInnerObjectList); However I'm not entirely sure how to do this so that the TreeSet orders the objects by the array properly. Is there an easy way to compare the "natural" order of elements in an array to each other? Only way I thought of was to check for size then if equal check contents until one index of one array is larger than the same index of another.
ex: the ordering would be like so {1,2,5} -> {1,2,4} -> {1,2,3}
Working with a list of Object where one of the item has an empty String. Trying to write method which would return a sorted list. By sorting means the first item value of the list should always be an empty String.
Since I don't want to manipulate the unsorted list, I am creating a new list to sort.
So far my code is:
private List<LoggerConfig> sort(List<LoggerConfig> unSortedList) {
List<LoggerConfig> sortedList = new ArrayList<LoggerConfig>(unSortedList);
//What to do here
return sortedList;
}
Looked at lot of SO posts but very confused.
You can trust the String.compareTo to match the order you seek. Here is a Comparator :
new Comparator<LoggerConfig>() {
#Override
public int compare(LoggerConfig o1, LoggerConfig o2) {
return (o1.getName().compareTo(o2.getName()));
}
};
or directly implementing Comparable in the specific class (here Dummy)
class Dummy implements Comparable<Dummy>{
String name;
public int compareTo(Dummy o) {
return this.name.compareTo(o.name);
}
}
The why :
The String.compareTo check the first characters of both to find a difference (until the smallest length of both), if they match, the lengths are use to make the difference, the longest will be after the shortest (shortest.compareTo(longuest) will return an negative value (the length difference)).
In this case, "".compareTo("abc"), there is no character in the empty String, so the first check is skipped and the length is use to compare the Strings, so an empty String will always be seen as first compare to any "non-empty" String
An example with the previous Dummy class (just need to add the Constructor Dummy(String):
public class Main {
public static void main(String[] args) {
List<Dummy> dummies = new LinkedList<Dummy>();
dummies.add(new Dummy("abc.com.core"));
dummies.add(new Dummy(""));
dummies.add(new Dummy("abc.com.core.def"));
System.out.println("BEFORE : " + dummies);
Collections.sort(dummies);
System.out.println("AFTER : " + dummies);
}
}
Output :
BEFORE : [abc.com.core, , abc.com.core.def]
AFTER : [, abc.com.core, abc.com.core.def]
You can place this condition in your comparator so that elements with an empty value are considered "less" than other elements, so that it shows up at the beginning of the sorted list. Try something like this:
Collections.sort(sortedList, new Comparator<LoggerConfig>() {
#Override
public int compare(LoggerConfig o1, LoggerConfig o2) {
if(o1.getName().isEmpty(){
return -1;
}
if(o2.getName().isEmpty(){
return 1;
}
return (o1.getName().compareTo(o2.getName()));
}
});
I didn't test this, but this should make the idea clear. If the empty element shows up at the end of the list, swap the -1 and the 1.
If your List is huge and sorting takes a lot of time, it might be a better idea to remove the empty element before sorting, then sort, then place the element at the beginning.
The Comparator solution seems feasible to me; what you're missing is implementing the compare method so that it does what you want.
Collections.sort(sortedList, new Comparator<LoggerConfig>() {
#Override
public int compare(LoggerConfig o1, LoggerConfig o2) {
if(o1.getName().equals("")){
return -1;
} else if(o2.getName().equals("")) {
return 1;
} else {
return (o1.getName().compareTo(o2.getName()));
}
}
});
As per Java docs, the Comparator has a compare method that returns an int which is
less than 0 if the first argument is less than the second
0 if the arguments are equal
greater than 0 if the first argument is greater than the second
So the Comparator you need should return the comparison of the two strings if they're both different from "", and -1 (or 1) if the first (or second) String is empty.
I need a Collection that sorts the element, but does not removes the duplicates.
I have gone for a TreeSet, since TreeSet actually adds the values to a backed TreeMap:
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
And the TreeMap removes the duplicates using the Comparators compare logic
I have written a Comparator that returns 1 instead of 0 in case of equal elements. Hence in the case of equal elements the TreeSet with this Comparator will not overwrite the duplicate and will just sort it.
I have tested it for simple String objects, but I need a Set of Custom objects.
public static void main(String[] args)
{
List<String> strList = Arrays.asList( new String[]{"d","b","c","z","s","b","d","a"} );
Set<String> strSet = new TreeSet<String>(new StringComparator());
strSet.addAll(strList);
System.out.println(strSet);
}
class StringComparator implements Comparator<String>
{
#Override
public int compare(String s1, String s2)
{
if(s1.compareTo(s2) == 0){
return 1;
}
else{
return s1.compareTo(s2);
}
}
}
Is this approach fine or is there a better way to achieve this?
EDIT
Actually I am having a ArrayList of the following class:
class Fund
{
String fundCode;
BigDecimal fundValue;
.....
public boolean equals(Object obj) {
// uses fundCode for equality
}
}
I need all the fundCode with highest fundValue
You can use a PriorityQueue.
PriorityQueue<Integer> pQueue = new PriorityQueue<Integer>();
PriorityQueue(): Creates a PriorityQueue with the default initial capacity (11) that orders its elements according to their natural ordering.
This is a link to doc: https://docs.oracle.com/javase/8/docs/api/java/util/PriorityQueue.html
I need all the fundCode with highest fundValue
If that's the only reason why you want to sort I would recommend not to sort at all. Sorting comes mostly with a complexity of O(n log(n)). Finding the maximum has only a complexity of O(n) and is implemented in a simple iteration over your list:
List<Fund> maxFunds = new ArrayList<Fund>();
int max = 0;
for (Fund fund : funds) {
if (fund.getFundValue() > max) {
maxFunds.clear();
max = fund.getFundValue();
}
if (fund.getFundValue() == max) {
maxFunds.add(fund);
}
}
You can avoid that code by using a third level library like Guava. See: How to get max() element from List in Guava
you can sort a List using Collections.sort.
given your Fund:
List<Fund> sortMe = new ArrayList(...);
Collections.sort(sortMe, new Comparator<Fund>() {
#Override
public int compare(Fund left, Fund right) {
return left.fundValue.compareTo(right.fundValue);
}
});
// sortMe is now sorted
In case of TreeSet either Comparator or Comparable is used to compare and store objects . Equals are not called and that is why it does not recognize the duplicate one
Instead of the TreeSet we can use List and implement the Comparable interface.
public class Fund implements Comparable<Fund> {
String fundCode;
int fundValue;
public Fund(String fundCode, int fundValue) {
super();
this.fundCode = fundCode;
this.fundValue = fundValue;
}
public String getFundCode() {
return fundCode;
}
public void setFundCode(String fundCode) {
this.fundCode = fundCode;
}
public int getFundValue() {
return fundValue;
}
public void setFundValue(int fundValue) {
this.fundValue = fundValue;
}
public int compareTo(Fund compareFund) {
int compare = ((Fund) compareFund).getFundValue();
return compare - this.fundValue;
}
public static void main(String args[]){
List<Fund> funds = new ArrayList<Fund>();
Fund fund1 = new Fund("a",100);
Fund fund2 = new Fund("b",20);
Fund fund3 = new Fund("c",70);
Fund fund4 = new Fund("a",100);
funds.add(fund1);
funds.add(fund2);
funds.add(fund3);
funds.add(fund4);
Collections.sort(funds);
for(Fund fund : funds){
System.out.println("Fund code: " + fund.getFundCode() + " Fund value : " + fund.getFundValue());
}
}
}
Add the elements to the arraylist and then sort the elements using utility Collections.sort,. then implement comparable and write your own compareTo method according to your key.
wont remove duplicates as well, can be sorted also:
List<Integer> list = new ArrayList<>();
Collections.sort(list,new Comparator<Integer>()
{
#Override
public int compare(Objectleft, Object right) {
**your logic**
return '';
}
}
)
;
I found a way to get TreeSet to store duplicate keys.
The problem originated when I wrote some code in python using SortedContainers. I have a spatial index of objects where I want to find all objects between a start/end longitude.
The longitudes could be duplicates but I still need the ability to efficiently add/remove specific objects from the index. Unfortunately I could not find the Java equivalent of the Python SortedKeyList that separates the sort key from the type being stored.
To illustrate this consider that we have a large list of retail purchases and we want to get all purchases where the cost is in a specific range.
// We are using TreeSet as a SortedList
TreeSet _index = new TreeSet<PriceBase>()
// populate the index with the purchases.
// Note that 2 of these have the same cost
_index.add(new Purchase("candy", 1.03));
Purchase _bananas = new Purchase("bananas", 1.45);
_index.add(new Purchase(_bananas);
_index.add(new Purchase("celery", 1.45));
_index.add(new Purchase("chicken", 4.99));
// Range scan. This iterator should return "candy", "bananas", "celery"
NavigableSet<PriceBase> _iterator = _index.subset(
new PriceKey(0.99), new PriceKey(3.99));
// we can also remove specific items from the list and
// it finds the specific object even through the sort
// key is the same
_index.remove(_bananas);
There are 3 classes created for the list
PriceBase: Base class that returns the sort key (the price).
Purchase: subclass that contains transaction data.
PriceKey: subclass used for the range search.
When I initially implemented this with TreeSet it worked except in the case where the prices are the same. The trick is to define the compareTo() so that it is polymorphic:
If we are comparing Purchase to PriceKey then only compare the price.
If we are comparing Purchase to Purchase then compare the price and the name if the prices are the same.
For example here are the compareTo() functions for the PriceBase and Purchase classes.
// in PriceBase
#Override
public int compareTo(PriceBase _other) {
return Double.compare(this.getPrice(), _other.getPrice());
}
// in Purchase
#Override
public int compareTo(PriceBase _other) {
// compare by price
int _compare = super.compareTo(_other);
if(_compare != 0) {
// prices are not equal
return _compare;
}
if(_other instanceof Purchase == false) {
throw new RuntimeException("Right compare must be a Purchase");
}
// compare by item name
Purchase _otherPurchase = (Purchase)_other;
return this.getName().compareTo(_otherChild.getName());
}
This trick allows the TreeSet to sort the purchases by price but still do a real comparison when one needs to be uniquely identified.
In summary I needed an object index to support a range scan where the key is a continuous value like double and add/remove is efficient.
I understand there are many other ways to solve this problem but I wanted to avoid writing my own tree class. My solution seems like a hack and I am surprised that I can't find anything else. if you know of a better way then please comment.
I'm not sure how to word this correctly, but I'm told to write a method that would return the largest course object (the course with the most students). If there are two courses that have the same number of students, it would return both.
The second part of the problem is what troubles me, because I'm not allowed to make another ArrayList other than the ones he specified (which is already used). Is there a way to keep track of two+ objects without using an list/hash?
This is what I've done so far, but it only returns one course object.
public Course largestEnrollment(){
int size = 0;
Course p = null;
for (Integer c : courseList.keySet()){
if (courseList.get(c).getClassList().size() > size){
p = courseList.get(c);
size = courseList.get(c).getClassList().size();
}
return p;
}
return null;
}
Return an array of Course objects:
public Course[] largestEnrollment(){
You'll need to decide how to manipulate the array inside your for loop.
Sort the ArrayList based on size. Then you can return a sub-list of the largest courses.
If you don't have so many Course (e.g. <1k), you could implement Comparable or write a Comparator for your Course object. So that you could just from the map get all Values(Course) in collection, then sort the collection, just from the end of the sorted collection take those elements with same values(size).
I mentioned the size of the collection because sort make the O(n) problem into O(nlogn). But if the size is small, it is a convenient way to go.
Anyway, you have to change the method return type to a collection or an array.
Sort then return a sublist:
public List<Course> largestEnrollment(List<Course> courses) {
Collections.sort(courses, new Comparator<Course>() {
#Override
public int compare(Course o1, Course o2) {
return o1.getClassList().size() - o2.getClassList().size();
}
});
for (int indexOfLargest = 1; indexOfLargest < courses.size(); indexOfLargest ++) {
if (courses.get(indexOfLargest - 1).getClassList().size() > courses.get(indexOfLargest).getClassList().size())
return courses.subList(0, indexOfLargest);
}
return courses;
}
I know that TreeSet stores objects in a sorted manner. But is there a way that i can customize the order?
For example if i have a treeSet:
TreeSet t1 = new TreeSet();
t1.add("c");
t1.add("d");
t1.add("a");
And now if i iterate over it>
Iterator it1 =t1.iterator();
while(it1.hasNext()){
Object o1 = it1.next();
System.out.println(o1);
}
i will always get the order as: a>c>d, however i want it to return the order the same as i added the elements in it i.e c>d>a?
Use LinkedHashSet for it,
TreeSet sorts the element, and for string it sorts based on natural order( this is how its comparator is implemented), If you want to manage the insertion order then you need to user LinkedHashSet
and if you don't need the uniquness (feature of set) then go for List
Since you mention about being bound to use TreeSet, something like this comes to my mind:
Set<String> result = new TreeSet<String>(new Comparator<String>(){
#Override
public int compare(String arg0, String arg1) {
return returnCode(arg0).compareTo(returnCode(arg1));
}
});
where:
private Integer returnCode(String p){
int code = 0;
String id = p.toLowerCase();
if ("a".equalsIgnoreCase(id)) code = 3;
else if ("b".equalsIgnoreCase(id)) code = 2;
else if ("c".equalsIgnoreCase(id)) code = 1;
//etc
return new Integer(code);
}
So basically you are implementing your own comparator which is nothing but assigning certain integer values to the inserted String (which i assume you know already).
NOTE: this solution will not work, incase you do not catch the option in your returnCode() method. I assume you already know the data that is being fed to the TreeSet.
It is much more easy:
TreeSet treeSetObj = new TreeSet(Collections.reverseOrder());
I have got a good answer. It's my first one.
import java.util.*;
class M
{
public static void main(String args[])
{
TreeSet<String> t=new TreeSet<>(new MyComparator());
t.add("c");
t.add("d");
t.add("a");
System.out.println(t);//[c,d,a] not [a,c,d] ....your answer
}
}
class MyComparator implements Comparator
{
public int compare(Object o1,Object o2)
{
String i1=(String)o1;
String i2=(String)o2;
return +1; //Store elements as they come
}
}
What basically +1 does store the elements in the order in which they come.
Always remember
if I write return +1 it means to store the elements in the order in which they come.
if I write return -1 it means to store the elements in reverse order in which they come.