I have 2 array lists. One is an array list containing birthdays. The other is an array list of names.
I am sorting the array list of dates in descending order by date using
Collections.sort(birthdayList);
I want to have the array list of names be sorted in the same order that the birthday list was.
i.e.
unsorted
bdaylist namelist
1/20/1980 - Bob
3/15/1970 - Todd
8/25/1990 - Jeff
becomes
sorted
3/15/1970 - Todd
1/20/1980 - Bob
8/25/1990 - Jeff
What would be the most efficient way to do this in Java?
Thank you very much!
Create a Person class with 2 fields: name and birthday.
Put the persons in a list
sort with a custom comparator that compares the birthdays
Create a class like this:
public class Person implements Comparable<Person> {
private String name;
private Date date;
public Person(String name, Date date) {
this.name = name;
this.date = date;
}
public String getName() {
return name;
}
public Date getDate() {
return date;
}
#Override
public int compareTo(Person o) {
return this.date.compareTo(o.getDate());
}
}
Then you can sort the list of Person objects like this:
public static void main(String... args) {
LinkedList<Person> persons = new LinkedList<Person>();
persons.add(new Person("Name1", new Date())); //Specify different dates
persons.add(new Person("Name2", new Date()));
persons.add(new Person("Name3", new Date()));
Collections.sort(persons);
//Collections.sort(persons, Collections.reverseOrder()); //Reverse order
}
That's it.
Or another alternative is to use Comparator:
Collections.sort(persons, new Comparator<Person>() {
#Override
public int compare(Person o1, Person o2) {
return o1.getDate().compareTo(o2.getDate());
}
});
Reverse order:
Collections.sort(persons, Collections.reverseOrder(new Comparator<Person>() {
#Override
public int compare(Person o1, Person o2) {
return o1.getDate().compareTo(o2.getDate());
}
}));
Then you don't need to implement Comparable<Person> in your person class.
Don't sort two array lists; sort one array list filled with combined objects containing both the date and the name. That's really the only way.
The other answers about implementing Comparable and using it as the comparator are all indeed correct. But, if this also helps...
According to the Javadoc for Collections.sort, it is noted that sort() uses Modified Mergesort as the sorting algorithm. Correct me if I am wrong, but it is widely accepted that Merge Sort achieves the best possible running time for the worst-case scenario out of all sorting algorithms out there: O(n log n) (I'm not eliminating the fact that there may be other sort algorithms that also achieve O(n log n) in the worst case).
But, O(n log n) is only the best possible run time for an unbounded domain of values. If you have a bound on your domain, then you can get an even better runtime of O(n) using Bucket Sort.
Related
I have the Person class:
public class Person implements Comparable<Person> {
private int id;
#Override
public int hashCode() {
return id;
}
#Override
public boolean equals(Object obj) {
Person other = (Person) obj;
return id == other.id;
}
#Override
public int compareTo(Person o) {
return Integer.compare(id, o.id);
}
}
And I have TreeSet of persons.
I need to implement method findPersonById(int id) in TreeSet.
I made it this way:
public Person find(int id) {
List<Person> personList = new ArrayList(idTreeSet);
Person pattern = new Person(id);
int index = Collections.binarySearch(personList, pattern);
return index < 0 ? null : personList.get(index);
}
Now the efficient of the find method is O(n) because it needs to copy all of elements from TreeSet to ArrayList.
But is there more efficient way to implement this method?
I don't need a Map. I'm interesed to resolve it without Maps.
Since you are prepared to allocate a temporary Person object, you can do it like this:
public Person find(int id) {
Person temp = new Person(id);
Person candidate = idTreeSet.ceiling(temp);
return temp.equals(candidate) ? candidate : null;
}
This is O(logN).
Note that we only create one temporary object here. If we use tailSet or subSet we will be creating at least second one; i.e. the NavigableSet returned by the tailSet or subSet call. (Looking under the hood of the TreeSet implementation, it looks like more will be created.)
If you don't need the properties of a TreeSet then using a HashMap<Integer, Person> or a HashSet<Person> would give you O(1) lookup. But in the latter case, you need change your Person class to satisfy the equals / hashCode contract.
Because TreeSet is a NavigableSet, you can use TreeSet.subSet, which leverages knowledge about the order of the elements to extract a range of elements as close as possible to the element you are interested in:
Person pattern = new Person(id);
return
// Get the Persons between pattern (inclusive) and pattern (inclusive).
// In other words: all the Persons with id equal to the input,
// of which there are zero or one.
idTreeSet.subSet(pattern, true, pattern, true).stream()
.findFirst()
.orElse(null);
Map<Integer, Person> personsById = new HashMap<>();
Would definitely be fastest, though not Tree based. A LinkedHashMap for order of insert would allow some order.
It is the more rugged solution.
I have values in linked list as
TY12354d,sfasdf,asfasf,2.35123412E8
TY12354dsaf,asdffasd,asfasfafsd,12344.0
Pranish,pranishfilan,viper,1234
zxs,asdf,asfd,1234
uv,vr,va,1234
www,dsf,ASDF,123
dsfgsdf,sd,sd,235
The values are seperated by commas which contains certain data. The first ones i.e TY12354d, TY12345saf, Pranish etc are the id, second i.e sfasdf, asdffasd, pranishfilan, etc are name.The values are viewed in jtextfield. I want to enable user to sort the datas according to the id when he clicks on "sort by id" button, name when he clicks on "sort by name" button and so on.
Try this one to sort by id.
LinkedList<String> list = new LinkedList<String>();
list.add("TY12354d,sfasdf,asfasf,2.35123412E8");
list.add("TY12354dsaf,asdffasd,asfasfafsd,12344.0");
list.add("Pranish,pranishfilan,viper,1234");
list.add("zxs,asdf,asfd,1234");
list.add("uv,vr,va,1234");
list.add("www,dsf,ASDF,123");
list.add("dsfgsdf,sd,sd,235");
Collections.sort(list, new Comparator<String>() {
public int compare(String a, String b) {
System.out.println(a+" --> "+b);
return a.substring(0, a.indexOf(',')).compareTo(b.substring(0, b.indexOf(',')));
}
});
Use same concept for name also.
output:
Pranish,pranishfilan,viper,1234
TY12354d,sfasdf,asfasf,2.35123412E8
TY12354dsaf,asdffasd,asfasfafsd,12344.0
dsfgsdf,sd,sd,235
uv,vr,va,1234
www,dsf,ASDF,123
zxs,asdf,asfd,1234
--EDIT--
as per OP last comment to compare on Car object
class Car {
String id;
String name;
public Car(String id, String name) {
this.id = id;
this.name = name;
}
// getter & setter
}
LinkedList<Car> list = new LinkedList<Car>();
list.add(new Car("TY12354d", "sfasdf"));
list.add(new Car("TY12354dsaf", "asdffasd"));
list.add(new Car("Pranish", "pranishfilan"));
list.add(new Car("zxs", "asdf"));
list.add(new Car("uv", "vr"));
list.add(new Car("www", "dsf"));
list.add(new Car("dsfgsdf", "sd"));
Collections.sort(list, new Comparator<Car>() {
public int compare(Car c1, Car c2) {
return c1.id.compareTo(c2.id);
}
});
You'll have to write your own comparator, or rewrite the structure. With a comparator you can simply use Collections.sort to sort the list.
There are many threads on implementing comparators here on stackoverflow, like this one. It's actually fairly simple.
It's not very efficient to sort a linked list, so if you don't use Collections.sort, which uses an intermediate array to sort, I'd suggest that you change your datastructure to e.g. an array or ArrayList. Or, even better: create a Class to represent your data and define comparators for that class.
Here's an example of a Comparator:
import java.util.*;
class Test {
static class IDComparator implements Comparator<String> {
#Override
public int compare(String a, String b) {
return a.split(",")[0].compareToIgnoreCase(b.split(",")[0]);
}
}
public static void main(String[] args) {
LinkedList<String> ll = new LinkedList<String>();
ll.add("TY12354d,sfasdf,asfasf,2.35123412E8");
ll.add("TY12354dsaf,asdffasd,asfasfafsd,12344.0");
ll.add("Pranish,pranishfilan,viper,1234");
System.out.println("Before sorting on ID:\n");
for (String s : ll) {
System.out.println(s);
}
Collections.sort(ll,new IDComparator());
System.out.println("\nAfter sorting on ID:\n");
for (String s : ll) {
System.out.println(s);
}
}
}
Output:
Before sorting on ID:
TY12354d,sfasdf,asfasf,2.35123412E8
TY12354dsaf,asdffasd,asfasfafsd,12344.0
Pranish,pranishfilan,viper,1234
After sorting on ID:
Pranish,pranishfilan,viper,1234
TY12354d,sfasdf,asfasf,2.35123412E8
TY12354dsaf,asdffasd,asfasfafsd,12344.0
This is not the prettiest code I've written. I especially don't like the comparator itself, with a hard coded index. However, it'll give you an idea of how to proceed with custom comparators.
I have an arraylist containing names, ages, salaries, etc.
I want to sort the list by name.
The following is what I have in my class:
//Sort by Name
public ArrayList<Employee> sortByName()
{
Collections.sort(employees);
return employees;
}
I have a comparator (which I'm not sure is even being used) here:
import java.util.*;
public class EmployeeNameComparator implements Comparator<Employee>
{
ArrayList<Employee> employees = new ArrayList<Employee>();
//METHODS
//Name Compare
public int compare(Employee object1, Employee object2)
{
return object1.getName().compareTo(object2.getName());
}
}
And here are the relevant parts of the tester I've made:
CompanyDataBase database = new CompanyDataBase();
database.addEmployee(new Employee("John James", 34, 45000));
database.addEmployee(new Employee("Josie Gibson", 19, 19000));
database.addEmployee(new Employee("Luke Marsden", 28, 30000));
database.addEmployee(new Manager("Aaron Morgan", 28, 44000, 5500));
System.out.println("\n\nSORT BY NAME");
//Collections.sort(database.getEmployees());
database.sortByName();
for(Employee currEmployee: database.getEmployees())
{
System.out.println(currEmployee.getDescription());
}
I've tried this loads of ways but nothing seems to be working, does anyone know where I'm going wrong or how to make it work? Thanks.
Sort objects by name using a comparator the second parameter required.
Collections.sort(employees, new EmployeeNameComparator());
See the example of using a custom comparator.
use the method Collections.sort(List<T> list, Comparator<? super T> c) to sort a collection with a given comparator
Collections.sort(employees, new EmployeeNameComparator());
We have a linkedlist, the elements of this linkedlist are Employee, I want to sort this linkedlist based on the salary of Employee, salary is one member of Employee Class, can we use Collections.sort()? if not, how can I sort it?
Can anyone explain me?
Yes, you can use Collections.sort()
You need to have your Employee class implement the Comparable interface.
http://download.oracle.com/javase/6/docs/api/java/lang/Comparable.html
In your compareTo() method you would compare the salary of the current object to that of the object passed in.
Edit:
The other option you have if you don't want that to be the default comparison is to create a Comparator object and use the second form -> Collections.sort(List, Comparator);
It would look like this:
class SalaryComparator implements Comparator<Employee>
{
public int compare(Employee e1, Employee e2)
{
if (e1.getSalary() > e2.getSalary())
return 1;
else if (e1.getSalary() < e2.getSalary())
return -1;
else
return 0;
}
}
Now you can do: Collections.sort(myEmployeeList, new SalaryComparator());
While a LinkedList<Employee> will work, I'd use an ArrayList<Employee> for this:
List<Employee> employees = new ArrayList<Employee>();
After you populate it (either way) you can sort it by salary like so:
Collections.sort(employees, new Comparator<Employee>() {
public int compare(Employee e1, Employee e2) {
return e1.getSalary() - e2.getSalary();
}
});
You can use Collections.sort()
But in order to do that, your Employee class needs to implement the Comparable interface first.
A rough example would be:
public class Employee implements Comparable<Employee>
{
public int compareTo(Employee e)
{
return this.salary - e.salary;
}
}
You can sort a linked list, but it's not an efficient operation, especially if the list is not trivial in size. Choose appropriate data structures.
This question already has answers here:
Sorting an ArrayList of objects using a custom sorting order
(12 answers)
Closed 6 years ago.
If I have a simple list of Strings:
List<String> stringList = new ArrayList<String>();
I can sort it with:
Collections.sort(stringList);
But suppose I have a Person class:
public class Person
{
private String name;
private Integer age;
private String country;
}
And a list of it:
List<Person> personList = new ArrayList<Person>();
And I want to sort it sometimes by name, sometimes by age, sometimes by country.
What is the easiest way to accomplish that?
I know that I can implement the Comparable interface, but that seems to limit me to sort it by one specific property.
Collections.sort can be called with a custom comparator. And that comparator can be implemented to allow sorting in different sort orders. Here's an example (for your Person model - with age as an Integer):
public class FlexiblePersonComparator implements Comparator<Person> {
public enum Order {Name, Age, Country}
private Order sortingBy = Name;
#Override
public int compare(Person person1, Person person2) {
switch(sortingBy) {
case Name: return person1.name.compareTo(person2.name);
case Age: return person1.age.compareTo(person2.age);
case Country: return person1.country.compareTo(person2.country);
}
throw new RuntimeException("Practically unreachable code, can't be thrown");
}
public void setSortingBy(Order sortBy) {
this.sortingBy = sortingBy;
}
}
And you use it like that (assuming persons is a field):
public void sortPersonsBy(FlexiblePersonComparator.Order sortingBy) {
List<Person> persons = this.persons; // useless line, just for clarification
FlexiblePersonComparator comparator = new FlexiblePersonComparator();
comparator.setSortingBy(sortingBy);
Collections.sort(persons, comparator); // now we have a sorted list
}
Implement the Comparator interface (once for each different sort order) and use the Collections.sort() method that takes a Comparator as additional parameter.
Thanks to the responders. For the benefit of others, I'd like to include a complete example.
The solution is the create the following additional classes:
public class NameComparator implements Comparator<Person>
{
public int compare(Person o1, Person o2)
{
return o1.getName().compareTo(o2.getName());
}
}
public class AgeComparator implements Comparator<Person>
{
public int compare(Person o1, Person o2)
{
return o1.getAge().compareTo(o2.getAge());
}
}
public class CountryComparator implements Comparator<Person>
{
public int compare(Person o1, Person o2)
{
return o1.getCountry().compareTo(o2.getCountry());
}
}
The list can then be sorted like this:
Collections.sort(personList, new NameComparator());
Collections.sort(personList, new AgeComparator());
Collections.sort(personList, new CountryComparator());
The Java 8 way of doing this is to use List.sort as follows:
personList.sort(Comparator.comparing(Person::getName));
To quote Stuart Marks in his answer over here.
This is the big advantage of the List.sort(cmp) extension method over Collections.sort(list, cmp). It might seem that this is merely a small syntactic advantage being able to write myList.sort(cmp) instead of Collections.sort(myList, cmp). The difference is that myList.sort(cmp), being an interface extension method, can be overridden by the specific List implementation. For example, ArrayList.sort(cmp) sorts the list in-place using Arrays.sort() whereas the default implementation implements the old copyout-sort-copyback technique.
You could also use the BeanComparator from apache commons beanutils, like this:
Collections.sort(personList, new BeanComparator("name"));
Implement 3 different types of Comparator.
you can add the comparator to the sort command. The comparator you define, will sort the elements by name, age, or what ever.
Collections.sort(list, new Comparator() {
public int compare(Object arg0, Object arg1) {
if (!(arg0 instanceof Person)) {
return -1;
}
if (!(arg1 instanceof Person)) {
return -1;
}
Person pers0 = (Person)arg0;
Person pers1 = (Person)arg1;
// COMPARE NOW WHAT YOU WANT
// Thanks to Steve Kuo for your comment!
return pers0.getAge() - pers1.getAge();
}
});
The Collections.sort method can be invoked with a second argument which is the comparator to use.
Create 3 comparators and use the one you want when appropriate.
Collections.sort(list , new Comparator() {
public int compare(Object o1, Object o2) {
...
}
});
Using lambdaj ( http://code.google.com/p/lambdaj/ ) you can achieve what you're asking in the following way:
sort(personList, on(Person.class).getName());
sort(personList, on(Person.class).getAge());
sort(personList, on(Person.class).getCountry());
I asked a very similar question (about searching rather than sorting), perhaps there is some useful information (I ended up using an enum that implements Comparator so I pass the enum value as a comparator selector).