Collections.sort that accept multiple parameters - java

I am new to Java. I am learning about Java Collections and I have question about writing a program to sort by attributes. So I have a class Course with these variables:
public class Course{
private String courseName;
private String courseDescription;
}
And another class Student that contains class Course which is a linked list of Course variables:
public class Student{
private String name;
private LinkedList<Course> courses;
}
public Student(String name) {
this.name = name;
this.courses = new LinkedList<Course>();
}
I want to write a method public void sortCourse() { } in Student class that should accept parameters to specify whether the sorting should be ascending or descending and also based on which course attribute to sort the courses, and print the sorted list of course. How can I write this method?

As Fureeish said in a comment: Make it accept a Comparator.
Like this:
public void sortCourse(Comparator<Course> comparator) {
this.courses.sort(comparator);
}
The caller would then write something like this:
// Sort ascending by name
student.sortCourse(Comparator.comparing(Course::getCourseName));
// Sort decending by name
student.sortCourse(Comparator.comparing(Course::getCourseName).reversed());
// Sort ascending by course level, then description
student.sortCourse(Comparator.comparing(Course::getCourseLevel)
.thenComparing(Course::getCourseDescription));

You can use Comparable interface to sort the courses. For that your Course class need to implements the Comparable interface.
public class Course implements Comparable <Course>{
private String courseName;
private String courseDescription;
public Course(String courseName, String courseDescription){
this.courseName = courseName;
this.courseDescription = courseDescription;
}
public int compareTo(Course c) {
return this.courseName.compareTo(c.courseName);
}
}
Now you can call Collections.sort(student.courses) method to sort the course list.
public class Student{
private String name;
private LinkedList<Course> courses;
public Student(String name) {
this.name = name;
this.courses = new LinkedList<Course>();
}
public void sortCourse(String sortOrder){
if(sortOrder.equals("asc")){
Collections.sort(this.courses);
} else {
Collections.sort(this.courses);
Collections.reverse(this.courses);
}
}
}

Related

Best way to add objects' field to a list

So I have this GameType class:
public class GameType {
private final String name;
public GameType(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
and I have a list of my game types, so, basically I want to print all of my GameType classes' name field and I am using Java 8, this is what I have done so far:
List<String> list = new ArrayList<>();
gameTypes.forEach(gameType -> list.add(gameType.getName()));
System.out.println(list);
So, what I am asking is, is there a better way to do that?
You can try this:
System.out.println(gameTypes.stream()
.map(GameType::getName)
.collect(Collectors.toList()));

How can I permit an ArrayList from removing added objects without overriding or making it immutable

Guys I have created an ArrayList and I don't want to make it immutable. I just seek to find a solution as for how to not allow the ArrayList from removing the objects.
public final class EMailArchive {
private final String name;
private final ArrayList <EMail> emailList;
private final LocalDate date;
public EMailArchive(String name, ArrayList <EMail> emailList) {
this.name = name;
this.emailList = emailList;
date = LocalDate.now();
}
public String getName() {
return name;
}
public LocalDate getDate( ) {
return date;
}
public List <EMail> getEMailList() {
return emailList;
}
public void addEMailToArchive(final EMail mail) {
emailList.add(mail);
// the mail added to the list shall not be removed, but how do i do that
}
}
One way is to implement a subClass of ArrayList that override the remove method
class myArrayLit extends ArrayList {
public myArrayList() {
super();
}
#Override
public remove(int index) {}
}
This is a basic example, there are more method to override, to achieve your goal.
If the solution above with extending ArrayList is not appropriate for whatever reason, you could return a copy within the getter, like this:
public List <EMail> getEMailList() {
return new ArrayList<>(emailList);
}
Changes to the returned List will not be reflected back to the class member.

Sorting an array alphabetically, but the array is full of objects, and I need to sort by a particular parameter

Let's say I have an object like:
public class Fruit{
private String name;
private int quantity;
Fruit(){}
Fruit(String name, int quantity){
this.name = name;
this.quantity= quantity;
}
public int getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
And I want to sort an array full of Fruit objects alphabetically by name. My initial thought, Arrays.sort(a.getName()); wouldn't work, because .getName() only works on individual objects. One idea I had was put all the names into an array, sort those alphabetically, then run a loop to sort the objects using this list, but that seems absurdly cumbersome.
Any ideas? As you can tell, I'm very new to working with objects in this manner.
Either you make your Fruit class Comparable by implementing the compareTo method, or you provide a custom Comparator to the Arrays.sort method:
Arrays.sort(fruits, Comparator.comparing(Fruit::getName));
This uses the Comparator.comparing method.
I recommend you redefine your Fruit class to implement Comparable<Fruit> so that you can easily sort a Fruit[] by each elements' respective name field:
public class Fruit implements Comparable<Fruit> {
// Code here...
#Override
public int compareTo(Fruit fruit) {
return name.compareTo(fruit.name);
}
}
Now, you can call Arrays#sort on Fruit[] and it will sort them lexicographically by name.
You don't need to make your Fruit class implement Comparable<Fruit>; you can do it by passing a custom Comparator to the array, like this:
Array<Fruit> sortedArray = sort(fruitArray, new Comparator<Fruit>() {
public int compare(Fruit left, Fruit right) {
return left.name.compareTo(right.name);
}
public int equals(Object obj) { return 0; /* you can ignore this */ }
});

Generic repository using map

I have a homework that specifies to add to an existent project a generic repository layer. The problem that i face is the following. My repository should encapsulate a map that stores the data. What I have until now is the following:
public interface IDObject<T> {
public Comparable<T> getID();
}
public class Person implements IDObject<String> {
private String cnp;
private String name;
private String age;
public Person(String cnp, String name, String age) {
this.cnp = cnp;
this.name = name;
this.age = age;
}
public void setName(String name) { this.name = name; }
public void setCNP(String cnp) { this.cnp = cnp; }
public void setAge(String age) { this.age = age; }
public String getName() { return name; }
public String getCNP() { return cnp; }
public String getAge() {return age; }
public String toString() { return cnp + "-" + name + "-" + age; }
#Override
public Comparable<String> getID() { return getCNP(); } //basically the unique identifier
}
public class Repository<T extends IDObject<?????????>>{
private IMap map;
public Repository() {
map = new Map<???????, T>();
}
...
}
So my problem appears in Repository class. I want to store persons so I will do something like Repository<Person> repo = new Repository<Person>(); But the problem is I don't know how to construct the map in the Repository constructor. In other words I don't know the type of the key. I want the Person's cnp to be the key(which is of Type String), but if I force the map to define the keys as Strings, my repository is no longer generic, because if I want to add some Animal objects that have the key as an integer , the map should be like map = new Map<Integer, T>();.
So the question is how can I still use a construction like Repository<Person> repo = new Repository<Person>(); using the fact that Objects that are stored in a repository implement IDObject and knowing that a repository encapsulates a map which stores the data? How should I get to know the key so I can complete the repository class?
You will have to introduce another generic type:
public class Repository<T, O extends IDObject<T>>
After that you can introduce StringIDRepository as
public class StringIDRepository<O extends IDObject<String>> extends Repository<String, O>
Alternative is to use Map<Object, O>, but that would require you to have in your Repository class getById method that takes Object as argument.
Hope this will help!

How do I use Java getters and setters with a collection of data without explicitly typing out the attributes for each item?

I am very new to Java and to programming in general, and I have an assessment to complete where I load employees (with name, age, and department attributes; department can be only one of four enumerated values) into a program that will sort them by age and tell if the age is a prime number. The assignment requires Company, Department, and Employee classes. I am confident that I can figure out age/prime components — I know how to google for algorithms. What I am struggling with is putting all the discrete pieces into a cohesive whole.
Here is what I have so far. I've put in one employee, but the way I'm doing it seems completely inelegant and inefficient. I am sure there is a better way, but I've hit a mental block.
EDIT: as was pointed out below, I was unclear. What I am asking help with is populating the data structure.
Company class:
public class Company {
static Employee one = new Employee();
public static void main(String[] args) {
one.setName("Counting Guru");
one.setAge(55);
one.setDepartment(DepartmentList.ACCOUNTING);
}
}
DepartmentList class:
import java.util.EnumMap;
import java.util.Map;
import java.util.Set;
public enum DepartmentList {
ACCOUNTING, MARKETING, HUMANRESOURCES, INFORMATIONSYSTEMS;
public static void main(String[] args) {
Map<DepartmentList,String>
enumMap=new EnumMap<DepartmentList,String>(DepartmentList.class);
enumMap.put(DepartmentList.ACCOUNTING, "Accounting");
enumMap.put(DepartmentList.MARKETING, "Marketing");
enumMap.put(DepartmentList.HUMANRESOURCES, "Human Resources");
enumMap.put(DepartmentList.INFORMATIONSYSTEMS, "Information Systems");
Set<DepartmentList> keySet = enumMap.keySet();
for (DepartmentList department : keySet) {
String value = enumMap.get(department);
System.out.println("ENUMMAP VALUE:"+value);
}
}
}
Employee class:
public class Employee {
String empName;
int empAge;
DepartmentList empDept;
Employee() {
}
public String getName() {
return empName;
}
public void setName(String name) {
this.empName = name;
}
public int getAge() {
return empAge;
}
public void setAge(int age) {
this.empAge = age;
}
public DepartmentList getDepartment() {
return empDept;
}
public void setDepartment(DepartmentList department) {
this.empDept = department;
}
public Employee(String empName, int empAge, DepartmentList empDept){
}
}
I also have a Department class, but it's currently empty.
Am I on the right track? Can someone give me a nudge? Thank you!
Don't hard-code the data inside the Java program. Put the data in a file and write methods to load the data.
If you MUST hardcode the data in the program, use something like this sample:
public class Employee
{
String name;
int age;
public Employee(String name, int age)
{
this.name = name;
this.age = age;
}
// getters, setters, etc.
}
In the main program
private static Employee[] empData =
{
new Employee("John Smith", 50),
new Employee("Fred Jones", 25),
.
.
.
};
Now you have a static array of Employee objects that you can "load" into your data structure.
If you're asking if there is something like a property in Java, no, there isn't (at least not yet).
If you're asking how to populate your objects something like an IOC container, like Spring, would be a better choice.
Now as it comes to your code you have two main methods in two different classes. Only one will be called. If you want to create a static instance you will be better do
static Employee one = new Employee("Counting Guru", 55, DepartmentList.ACCOUNTING);
or
static Employee one = new Employee();
static {
one.setName("Counting Guru");
one.setAge(55);
one.setDepartment(DepartmentList.ACCOUNTING);
}
When it comes to the enum then you'll better define a constructor for it
public enum DepartmentList {
ACCOUNTING("Accounting"), MARKETING("Marketing");
private String displayName;
public DepartmentList(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return diplayName;
}
}
In the Employee constructor you need to assign the field values to the ones received as arguments.

Categories