How to insert Java object into an ArrayList? - java

I have a problem trying to insert a calculated result into an ArrayList of Student's list of results.
It goes like this.
An ArrayList (called FullList) holds a list of Student objects.
A Student object has a name (as a String) and a resultslist (as an ArrayList).
When i receive a Result object, it comes with a name (as a String) and result (as a Integer).
I want to insert this Result object into the Student object's resultlist.
However, the student names are not defined upfront but deduced upon the receipt of a Results object.
That is to say, if there is no Student object in FullList, the Result object will trigger the creation of a Student object and insert itself into the Student object's resultslist.
Then the created Student object will be inserted into FullList.
I have written the code below but I'm getting multiple insertions of the same tag into FullList instead of insertion of multiple results into each tag.
Q1: I can't figure out what's wrong! Need a mind prick from the Gurus!
Q2: I will be using the following code for up to 90,000 students. Is this a feasible way of housing student results?
class Result {
String name;
int result;
public Result(String name, int result) {
this.name = name;
this.result = result;
}
/* start - Getting hungup over this method
* Something is wrong here and i don't know what it is
*/
public void setResult(ArrayList <Student> fullList) {
for (Student s : fullList) {
if (s.getName().equalsIgnoreCase(this.name)) {
s.setResult(this);
}
else { /* enters here if Student does not exist in fullList */
Student s = new Student(this.name); /* create new student */
s.setResult(this); /* insert result into Student's resultslist */
fullList.add(s); /* add Student into fullList */
}
}
}
/* end */
public String getName() {
return this.name;
}
}
class Student {
String name;
ArrayList <Result> resultslist;
public Student(String name) {
this.name = name;
resultslist = new ArrayList <Result> ();
}
public void setResult(Result result) {
this.resultslist.add(result);
}
public String getName() {
return this.name;
}
}
class StudentResults {
public static void main (String [] args) {
ArrayList <Student> FullList = new ArrayList <Student> ();
Result r1 = new Result("John", 12);
Result r2 = new Result("Jamie", 99);
Result r3 = new Result("John", 69);
Result r4 = new Result("Jacque", 56);
Result r5 = new Result("Jacque", 100);
Result r6 = new Result("Jamie", 100);
r1.setResult(FullList);
r2.setResult(FullList);
r3.setResult(FullList);
r4.setResult(FullList);
r5.setResult(FullList);
r6.setResult(FullList);
}
}

For each student in the list, you're inserting a new student if this student doesn't have the same name as the result to insert:
for (Student s : fullList) {
if (s.getName().equalsIgnoreCase(this.name)) { // current student has same name as result
s.setResult(this);
}
else { // current student doesn't have the same name as result
Student s = new Student(this.name);
s.setResult(this);
fullList.add(s);
}
}
The above should be written as:
Student s = findStudentWithName(fullList, this.name);
if (s == null) {
Student s = new Student(this.name);
s.setResult(this);
fullList.add(s);
}
else {
s.setResult(this);
}
And the findStudentWithName method would look like this:
private Student findStudentWithName(List<Student> students, String name) {
for (Student s : students) {
if (s.getName().equalsIgnoreCase(name)) {
return s;
}
}
// no student found.
return null;
}

Use Map/HashMap in place of List as:
Map<String, Student> fullStudents= new HashMap<Student>();
and use it as:
public void setResult(Map<String, Student> fullMap) {
Student s = fullMap.get(this.name.toLowerCase());
if(s == null){
s = new Student(this.name);
fullMap.put(this.name.toLowerCase(), s);
}
s.setResult(this);
}
Its much simpler and cleaner.
Also to get the list of Students any time, you can simply do:
List<Student> fullList = fullMap.values();

Related

Hierarchical Data to arrayList using recursion. (Java)

I have hierarchical data in MySQL of employees and their subordinates as shown here There is a joining column 'managerID' which references to the employee ID in the same column.
My objective is to recursively go through this data and add it all to an arrayList which would end up looking like this:
[Tom [Hanna [George [Chris], Rachel]]]
But there is a logic problem in my java function:
public void getList(String employeeName, ArrayList<Object> arrayList) {
// Initialise the arrayList the first time
if (arrayList == null) {
arrayList = new ArrayList<>();
}
// Using the string provided, I have found the employee
Employee employee = employeeRepository.findByName(employeeName);
// adding employee to the list
arrayList.add(employee);
// Getting list of employee's subordinates
List<Employee> subordinates = employee.getSubordinates();
// Checking if employee has subordinates
if (subordinates != null) {
// Iterate through each of their subordinates and call recursive function
for (int i = 0; i < subordinates.size(); i++) {
ArrayList<Object> subOrdinateDetails = new ArrayList<>();
// If the subordinate has subordinates, use recursion
if (subordinates.get(i).getSubordinates() != null) {
getList(subordinates.get(i).getName(), subordinatesDetails);
}
// Adding this list to the original arrayList
arrayList.add(subOrdinateDetails);
}
System.out.println(arrayList.toString());
}
}
The toString method at the end of the method does not print what I wanted above, instead it prints:
[Chris]
[George, [Chris]]
[Rachel]
[Hanna, [George, [Chris]], [Rachel]]
[Tom, [Hanna, [George, [Chris]], [Rachel]]]
While trying to debug it, I tried to get the first index of the arrayList, to understand what it was here is what it printed:
Chris
George
Rachel
Hanna
Tom
As you can tell, I am new to java, and I have failed debugging my code. If you could point out my mistake, I will be very grateful.
You can simply do it like this.
public class Employee {
private final String name;
private final List<Employee> subordinates;
public Employee(String name, List<Employee> subordinates) {
super();
this.name = name;
this.subordinates = subordinates;
}
public String getName() {
return name;
}
public List<Employee> getSubordinates() {
return subordinates;
}
public void print() {
System.out.println(this.name);
this.subordinates.forEach(emp -> {
emp.print();
});
}
}
public class EmployeeTest {
public static void main(String[] args) {
Employee chris = new Employee("chris", new ArrayList<>());
Employee george = new Employee("george", Arrays.asList(chris));
Employee rachell = new Employee("rachell", new ArrayList<>());
Employee hannah = new Employee("hannan", Arrays.asList(george, rachell));
Employee tom= new Employee("tom",Arrays.asList(hannah));
tom.print();
}
}
The trick in the recursion is each time it prints out the current employee, before printing any of it's subordinates as you can see in the method. I'll leave it to you to come up with the brackets if needed.

Multiple NULL addition into a List in Java

I have 2 lists and want to copy some element from one to another, i.e. there are old and new employees list I need to union 2 lists and delete the elements that include to the old list but not include in the new one.
I could solve the part of getting the union and intersection by using TreeSet and override the equals and hashcode functions of the Employees class....
Now, I want to exclude the elements that are in the old but not in the new and add them to the "deletedList"....which I got "ConcurrentModificationException"
I tried this instead of "iterator" but the same result: for(Employees e : employeesListDB)
Also I tried "CopyOnWriteArrayList" instead of "ArrayList" but no change!!
but the problem now that at the initialization of the empty list "deletedList" it is filled with multiple null elements before the add function!
Here is the code:
List<Employees> employeesListDB = this.findAll();
Set<Employees> empSet = new TreeSet<Employees>(new EmployeeComparator());
empSet.addAll(employeesList);
List<Employees> deletedList = new ArrayList<Employees>();
Employees e = new Employees();
ListIterator<Employees> itr = employeesListDB.listIterator();
for(itr.hasNext()) {
e = (Employees)itr.next();
if(!empSet.contains(e)) {
deletedList.add(e);
}
}
A counter Example:
The oldlist "employeesListDB" the employees list from the database:
[
{
"email":"mariam.moustafa#x.com"
},
{
"email":"sara.ahmed#x.com"
},
{
"email":"ali.hassan#x.com"
},
{
"email":"hoosen.imam-ally#x.com"
},
{
"email":"allan.randall#x.com"
},
{
"email":"nishaan.maharaj#x.com"
}
]
The new list to be added:
[
{
"email":"ali.moustafa#x.com"
},
{
"email":"sara.ahmed#x.com"
},
{
"email":"emad.hamed#x.com"
}
]
The deleted list that I want:
[
{
"email":"mariam.moustafa#x.com"
},
{
"email":"ali.hassan#x.com"
},
{
"email":"hoosen.imam-ally#x.com"
},
{
"email":"allan.randall#x.com"
},
{
"email":"nishaan.maharaj#x.com"
}
]
Sara mail will be updated...
Employee class has two fields {id,email} the new list (the list to be added to the db) is a list of only emails, id field are not recognized yet but the old list has the complete bean fields ...to compare between these 2 list I should override the Comparator to ignore the id field; Finding duplicates in a List ignoring a field
JUST I need to know, why when I use set.add operation, it adds the unique emails only! the original size of the list was 36 elements after adding it into a set it becomes only 16!!
Set<Employees> oldSet = new TreeSet<Employees>(new EmployeeComparator());
oldSet.addAll(employeesListDB);
Set<Employees> newSet = new TreeSet<Employees>(new EmployeeComparator());
newSet.addAll(employeesList);
Set<Employees> deleted = Sets.difference(oldSet, newSet);
As I understand, you need all elements that are contained by old set and not contained by new set.
For this purpose you can use Guava Sets#difference method:
Set<Employees> deleted = Sets.difference(oldSet, newSet);
Test with your data:
Set<String> oldEmployees = Sets.newHashSet("mariam.moustafa#x.com", "sara.ahmed#x.com", "ali.hassan#x.com", "hoosen.imam-ally#x.com", "allan.randall#x.com", "nishaan.maharaj#x.com");
Set<String> newEmployees = Sets.newHashSet("ali.moustafa#x.com", "sara.ahmed#x.com", "emad.hamed#x.com");
Set<String> diff = Sets.difference(oldEmployees, newEmployees);
System.out.println(diff);
Result:
[nishaan.maharaj#x.com, mariam.moustafa#x.com, ali.hassan#x.com, allan.randall#x.com, hoosen.imam-ally#x.com]
Here is a core Java solution using 2 simple steps:
[1] - Create a set setOld which contains the first set of emails
[2] - Subtract from setOld a new set of emails setNew
Set oldSet<String> = new HashSet<String>(); // original set of email addresses
oldSet.add("mariam.moustafa#x.com");
oldSet.add("sara.ahmed#x.com");
oldSet.add("ali.hassan#x.com");
oldSet.add("hoosen.imam-ally#x.com");
oldSet.add("allan.randall#x.com");
oldSet.add("nishaan.maharaj#x.com");
Set newSet<String> = new HashSet<String>(); // new set of email addresses
newSet.add("ali.moustafa#x.com");
newSet.add("sara.ahmed#x.com");
newSet.add("emad.hamed#x.com");
for (String s : newSet) {
oldSet.remove(s); // this will only remove the element if found
}
// display new contents of oldSet
for (String s : oldSet) {
System.out.println(s);
}
Output:
mariam.moustafa#x.com
ali.hassan#x.com
hoosen.imam-ally#x.com
allan.randall#x.com
nishaan.maharaj#x.com
Try it this way (Made a small TestCase):
private static Employee createEmployee(String string) {
Employee employee = new Employee();
employee.setEmail(string);
return employee;
}
public static void main(String[] args) {
List<String> newMails = new ArrayList<>();
List<Employee> oldList = new ArrayList<>();
oldList.add(createEmployee("mariam.moustafa#x.com"));
oldList.add(createEmployee("sara.ahmed#x.com"));
oldList.add(createEmployee("ali.hassan#x.com"));
oldList.add(createEmployee("hoosen.imam-ally#x.com"));
oldList.add(createEmployee("allan.randall#x.com"));
oldList.add(createEmployee("nishaan.maharaj#x.com"));
newMails.add("ali.moustafa#x.com");
newMails.add("sara.ahmed#x.com");
newMails.add("emad.hamed#x.com");
List<Employee> delete = new ArrayList<>();
Set<String> removedMails = new HashSet<>();
for (Employee emp : oldList) {
if (!newMails.contains(emp.getEmail())) {
delete.add(emp);
}
removedMails.add(emp.getEmail());
}
newMails.removeAll(removedMails);
// remove emploeyees in delete
oldList.removeAll(delete);
// Create employee for left MAils
for (String newMail : newMails) {
oldList.add(createEmployee(newMail));
}
//Old and new Employees
for (Employee emp : oldList) {
System.out.println(emp.getEmail());
}
}
simple Employee class:
class Employee {
String email;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
output:
sara.ahmed#x.com
ali.moustafa#x.com
emad.hamed#x.com
the empty list filled with multiple null elements before the add
function!
This is becuase you're using the ArrayList which contains the following constant:
private static final int DEFAULT_CAPACITY = 10;
Which mean when you create the ArrayList<T> with the new operator you actually create an Array of T which contains 10 nulls (It's contained as private transient Object[] elementData field).
The JLS said:
Every variable in a program must have a value before its value is
used:
Each class variable, instance variable, or array component is initialized with a default value when it is created (§15.9, §15.10.2):
[...]
For all reference types (§4.3), the default value is null.
Use List removeAll method. You will need to override equals method in your Employees class. PFB sample snippet based on employee id, you will need to modify it to fit based on email id:
import java.util.*;
public class StringArray {
public static void main(String args[]) {
List<Employee> oldList = new ArrayList<Employee>();
oldList.add(new Employee(1));
oldList.add(new Employee(2));
oldList.add(new Employee(3));
oldList.add(new Employee(4));
List<Employee> newList = new ArrayList<Employee>();
newList.add(new Employee(3));
newList.add(new Employee(4));
newList.add(new Employee(5));
newList.add(new Employee(6));
oldList.removeAll(newList);
System.out.println("Printing delete list");
for (Employee employee : oldList)
System.out.println(employee);
System.out.println("Printing updated list");
for (Employee employee : newList)
System.out.println(employee);
}
}
public class Employee {
private int id;
public Employee(int id) {
super();
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Override
public String toString() {
return "Employee [id=" + this.id + "]";
}
#Override
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Employee))
return false;
Employee c = (Employee) o;
return this.id == c.id;
}
}

Create an ArrayList with multiple object types?

How do I create an ArrayList with integer and string input types? If I create one as:
List<Integer> sections = new ArrayList <Integer>();
that will be an Integer type ArrayList.
If I create one as:
List<String> sections = new ArrayList <String>();
that will be of String type.
How can I create an ArrayList which can take both integer and string input types?
Thank you.
You can make it like :
List<Object> sections = new ArrayList <Object>();
(Recommended) Another possible solution would be to make a custom model class with two parameters one Integer and other String. Then using an ArrayList of that object.
(1)
ArrayList<Object> list = new ArrayList <>();`
list.add("ddd");
list.add(2);
list.add(11122.33);
System.out.println(list);
(2)
ArrayList arraylist = new ArrayList();
arraylist.add(5);
arraylist.add("saman");
arraylist.add(4.3);
System.out.println(arraylist);
You can use Object for storing any type of value for e.g. int, float, String, class objects, or any other java objects, since it is the root of all the class. For e.g.
Declaring a class
class Person {
public int personId;
public String personName;
public int getPersonId() {
return personId;
}
public void setPersonId(int personId) {
this.personId = personId;
}
public String getPersonName() {
return personName;
}
public void setPersonName(String personName) {
this.personName = personName;
}}
main function code, which creates the new person object, int, float, and string type, and then is added to the List, and iterated using for loop. Each object is identified, and then the value is printed.
Person p = new Person();
p.setPersonId(1);
p.setPersonName("Tom");
List<Object> lstObject = new ArrayList<Object>();
lstObject.add(1232);
lstObject.add("String");
lstObject.add(122.212f);
lstObject.add(p);
for (Object obj : lstObject) {
if (obj.getClass() == String.class) {
System.out.println("I found a string :- " + obj);
}
if (obj.getClass() == Integer.class) {
System.out.println("I found an int :- " + obj);
}
if (obj.getClass() == Float.class) {
System.out.println("I found a float :- " + obj);
}
if (obj.getClass() == Person.class) {
Person person = (Person) obj;
System.out.println("I found a person object");
System.out.println("Person Id :- " + person.getPersonId());
System.out.println("Person Name :- " + person.getPersonName());
}
}
You can find more information on the object class on this link Object in java
List<Object> list = new ArrayList<>();
list.add(1);
list.add("1");
As the return type of ArrayList is object, you can add any type of data to ArrayList but it is not a good practice to use ArrayList because there is unnecessary boxing and unboxing.
You could create a List<Object>, but you really don't want to do this. Mixed lists that abstract to Object are not very useful and are a potential source of bugs. In fact the fact that your code requires such a construct gives your code a bad code smell and suggests that its design may be off. Consider redesigning your program so you aren't forced to collect oranges with orangutans.
Instead -- do what G V recommends and I was about to recommend, create a custom class that holds both int and String and create an ArrayList of it. 1+ to his answer!
Create your own class which stores the string and integer, and then make a list of these objects.
class Stuff {
private String label;
private Integer value;
// Constructor
public void Stuff(String label, Integer value) {
if (label == null || value == null) {
throw NullPointerException();
}
this.label = label;
this.value = value;
}
// getters
public String getLabel() {
return this.label;
}
public Integer getValue() {
return this.value;
}
}
Then in your code:
private List<Stuff> items = new ArrayList<Stuff>();
items.add(new Stuff(label, value));
for (Stuff item: items) {
doSomething(item.getLabel()); // returns String
doSomething(item.getValue()); // returns Integer
}
It depends on the use case. Can you, please, describe it more?
If you want to be able to add both at one time, than you can do the which is nicely described by #Sanket Parikh. Put Integer and String into a new class and use that.
If you want to add the list either a String or an int, but only one of these at a time, then sure it is the List<Object>
which looks good but only for first sight! This is not a good pattern. You'll have to check what type of object you have each time you get an object from your list. Also This type of list can contain any other types as well.. So no, not a nice solution. Although maybe for a beginner it can be used. If you choose this, i would recommend to check what is "instanceof" in Java.
I would strongly advise to reconsider your needs and think about maybe your real nead is to encapsulate Integers to a List<Integer> and Strings to a separate List<String>
Can i tell you a metaphor for what you want to do now? I would say you want to make a List wich can contain coffee beans and coffee shops. These to type of objects are totally different! Why are these put onto the same shelf? :)
Or do you have maybe data which can be a word or a number? Yepp! This would make sense, both of them is data! Then try to use one object for that which contains the data as String and if needed, can be translated to integer value.
public class MyDataObj {
String info;
boolean isNumeric;
public MyDataObj(String info){
setInfo(info);
}
public MyDataObj(Integer info){
setInfo(info);
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
this.isNumeric = false;
}
public void setInfo(Integer info) {
this.info = Integer.toString(info);
this.isNumeric = true;
}
public boolean isNumeric() {
return isNumeric;
}
}
This way you can use List<MyDataObj> for your needs. Again, this depends on your needs! :)
Some edition: What about using inharitance? This is better then then List<Object> solution, because you can not have other types in the list then Strings or Integers:
Interface:
public interface IMyDataObj {
public String getInfo();
}
For String:
public class MyStringDataObj implements IMyDataObj {
final String info;
public MyStringDataObj(String info){
this.info = info;
}
#Override
public String getInfo() {
return info;
}
}
For Integer:
public class MyIntegerDataObj implements IMyDataObj {
final Integer info;
public MyIntegerDataObj(Integer info) {
this.info = info;
}
#Override
public String getInfo() {
return Integer.toString(info);
}
}
Finally the list will be: List<IMyDataObj>
You don't know the type is Integer or String then you no need Generic. Go With old style.
List list= new ArrayList ();
list.add(1);
list.add("myname");
for(Object o = list){
}
You can always create an ArrayList of Objects. But it will not be very useful to you. Suppose you have created the Arraylist like this:
List<Object> myList = new ArrayList<Object>();
and add objects to this list like this:
myList.add(new Integer("5"));
myList.add("object");
myList.add(new Object());
You won't face any problem while adding and retrieving the object but it won't be very useful.
You have to remember at what location each type of object is it in order to use it. In this case after retrieving, all you can do is calling the methods of Object on them.
You can just add objects of diffefent "Types" to an instance of ArrayList. No need create an ArrayList. Have a look at the below example,
You will get below output:
Beginning....
Contents of array: [String, 1]
Size of the list: 2
This is not an Integer String
This is an Integer 1
package com.viswa.examples.programs;
import java.util.ArrayList;
import java.util.Arrays;
public class VarArrayListDemo {
#SuppressWarnings({ "rawtypes", "unchecked" })
public static void main(String[] args) {
System.out.println(" Beginning....");
ArrayList varTypeArray = new ArrayList();
varTypeArray.add("String");
varTypeArray.add(1); //Stored as Integer
System.out.println(" Contents of array: " + varTypeArray + "\n Size of the list: " + varTypeArray.size());
Arrays.stream(varTypeArray.toArray()).forEach(VarArrayListDemo::checkType);
}
private static <T> void checkType(T t) {
if (Integer.class.isInstance(t)) {
System.out.println(" This is an Integer " + t);
} else {
System.out.println(" This is not an Integer" + t);
}
}
}
Just use Entry (as in java.util.Map.Entry) as the list type, and populate it using (java.util.AbstractMap’s) SimpleImmutableEntry:
List<Entry<Integer, String>> sections = new ArrayList<>();
sections.add(new SimpleImmutableEntry<>(anInteger, orString)):
For me this method works perfectly fine in jdk 16
import java.util.ArrayList;
public class Array {
public static void main(String[] args) {
ArrayList arrayList= new ArrayList();
arrayList.add("alien");
arrayList.add(1);
arrayList.add(0,'b');
System.out.println(arrayList);
System.out.println((arrayList.get(0)) instanceof Integer);
}
}
Output
[b, alien, 1]
false
User Defined Class Array List Example
import java.util.*;
public class UserDefinedClassInArrayList {
public static void main(String[] args) {
//Creating user defined class objects
Student s1=new Student(1,"AAA",13);
Student s2=new Student(2,"BBB",14);
Student s3=new Student(3,"CCC",15);
ArrayList<Student> al=new ArrayList<Student>();
al.add(s1);
al.add(s2);
al.add(s3);
Iterator itr=al.iterator();
//traverse elements of ArrayList object
while(itr.hasNext()){
Student st=(Student)itr.next();
System.out.println(st.rollno+" "+st.name+" "+st.age);
}
}
}
class Student{
int rollno;
String name;
int age;
Student(int rollno,String name,int age){
this.rollno=rollno;
this.name=name;
this.age=age;
}
}
Program Output:
1 AAA 13
2 BBB 14
3 CCC 15

getting ConcurrentModificationException error while using iterator and remove

I am getting a java.util.ConcurrentModificationException from following code and I can find the reason. I could successfully read data form a csv file and make an arraylist called course list of it. then I need to sort my in to an array list that each of its cell contains an arraylist of identical courses (courses that have similar name).
But when I run it generates ConcurrentModificationException and I do not understand why...
public class CourseLister {
private static final String DATA = "data\\data.csv";
File file;
ArrayList<Course> courseList ;
public CourseLister(String filepath) {
file = new File(filepath);
courseList = new ArrayList<>();
}
public void readFromCsv(){
// in this method a Csv file is written line by line , create a new object of course with some attribute such as name , number, instructor,... and is added to courseList //}
}
public Iterator<Course> getCourseIterator(){
return courseList.iterator();
}
public ArrayList<Course> getCourseList(){
return courseList;
}
public static void main(String [ ] args){
CourseLister courseLister = new CourseLister(DATA);
courseLister.readFromCsv();
CourseFileSorter coursefilesoreter = new CourseFileSorter(courseLister.getCourseIterator());
ArrayList<Course> curseList = courseLister.getCourseList();
for (Course course : curseList) {
System.out.println(course.getSemester());
}
System.out.println(curseList.size());
coursefilesoreter.displayCategorizedList();
}
}
here is my CourefileSorterclass:
public class CourseFileSorter {
Iterator<Course> courseItr ;
public CourseFileSorter(Iterator<Course> courseItr) {
this.courseItr = courseItr;
}
public ArrayList<ArrayList<Course>> getSourtedLists(){
Iterator<Course> dissimilarCourseItr = null;
ArrayList<Course> identicalCourseList = new ArrayList<Course>();
ArrayList<Course> dissimilarCourseList = new ArrayList<Course>();
ArrayList<ArrayList<Course>> categorizedCourseList = new ArrayList<ArrayList<Course>>();
Course firstCourse = null;
Course currentCourse ;
if(courseItr.hasNext()){
while(courseItr.hasNext()){
firstCourse = courseItr.next();
identicalCourseList.add(firstCourse);
while(courseItr.hasNext()){
currentCourse = courseItr.next();
if(currentCourse.getCourseName().equals(firstCourse.getCourseName())){
identicalCourseList.add(currentCourse);
courseItr.remove();
}
else{
dissimilarCourseList.add(currentCourse);
}
}
dissimilarCourseItr = dissimilarCourseList.iterator();
courseItr = dissimilarCourseItr;
categorizedCourseList.add(identicalCourseList);
}
return categorizedCourseList;
}
else{
return null;
}
}
}
It would be much easier to sort them into a different data structure. I see that course has a getCourseName() method, which I assume would return a String object. Try using a Map<String, List<Course>> instead.
The sorting method would look like this:
public Map<String, List<Course>> getSourtedLists(){
Map<String, List<Course>> result = new HashMap<String, List<Course>>();
while(courseItr.hasNext()) {
course next = courseItr.next();
if (!result.containsKey(next.getCourseName())) {
result.put(next.getCourseName(), new ArrayList<Course>());
}
result.get(next.getCourseName()).add(next);
}
Also, you REALLY don't want to call courseItr.remove(); This removes the course object from the underlying Collection, meaning that the way you were planning to do it would empty out the courseList from your CourseLister object.
1 . You get ConcurrentModificationException because:
dissimilarCourseList.add(currentCourse);
courseItr = dissimilarCourseItr;
2 . It's not a good idea to use iterators when you have arraylists.

Copying contents of file into array of linked list and sort it

I have a comma separated file that contains
Employee name,company,years.
An employee may be affiliated to multiple companies.
For eg,
John,Google,2
John,Microsoft,1
James,Tesla,1
James,Apple,5
I have retrieved the information using the java scanner
scanner.useDelimiter(",|\\n");
while (scanner.hasNext()) {
String line = scanner.next()
I am new to Java and I am trying to insert the above in a sorted order (using experience as sorting criteria) using an array of linked lists or array of array. So
employee -> Company1 -> Company2.... (ordered by employee experience)
So in the above example, it would be:
John->Microsoft->google
James->Tesla->Apple
Can someone point me to the right direction?
NOTE: If the experience is same, it doesnt matter which company comes first.
Use this class for Person
public class Person {
#Getter #Setter
private String name;
#Getter #Setter
private TreeMap<String, String> companyExperience;
public Person(){
companyExperience = new TreeMap<String, String>();
}
}
Using the experience as key in a TreeMap will automatically sort the companies for a Person in ascending order.
Your main class shoud look like this
public class App
{
public static void main( String[] args )
{
HashMap<String, Person> persons = new HashMap<String, Person>();
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("C:\\Users\\Public Administrator\\test.txt"));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String line = null;
try {
while ((line = br.readLine()) != null) {
String[] fields = line.split(",");
String personName = fields[0];
Person existingPerson = persons.get(personName);
if (existingPerson==null){
Person newPerson = new Person();
newPerson.setName(personName);
newPerson.getCompanyExperience().put(Integer.parseInt(fields[2])+fields[1], fields[1]);
persons.put(personName, newPerson);
} else{
existingPerson.getCompanyExperience().put(Integer.parseInt(fields[2])+fields[1], fields[1]);
}
}
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//output
Iterator<Map.Entry<String, Person>> entries = persons.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<String, Person> entry = entries.next();
Person _person = entry.getValue();
System.out.print(_person.getName());
Iterator<Map.Entry<String, String>> companyExperiences = _person.getCompanyExperience().entrySet().iterator();
while (companyExperiences.hasNext()) {
Map.Entry<String, String> companyExperience = companyExperiences.next();
System.out.print(" > "+companyExperience.getValue());
}
System.out.println();
}
}
}
I've tested it and looks pretty, pretty good to me.
By the way, the #Getter and #Setter annotations are from the Lombok project. You can either use it or create your own getters/setters.
read your file with readLine() and use split to get each field of your data, e.g.:
BufferedReader br = new BufferedReader(new FileReader("FileName"));
String line = null;
ArrayList<Person> list = new ArrayList<Person>();
while ((line = br.readLine()) != null) {
String[] fields = line.split(",");
list.add(new Person(fields[0], fields[1], Integer.parseInt(fields[2])));
}
You can then save your data in ArrayList that takes a custom class e.g. Person that stores the person's information and implements Comparable where you do the sorting logic.
If you need to group your data by the person name, you might consider having a Hashtable where the key is the person name and the value is ArrayList of experience.
You can define a class for your data, e.g.
class Person implements Comparable<Person> {
private String name;
private String company;
private int experience;
public Person(String name, String company, int experience) {
this.name = name;
this.company = company;
this.experience = experience;
}
public int getExperience() {
return experience;
}
#Override
public int compareTo(Person person) {
return new Integer(experience).compareTo(person.getExperience());
}
}
The to sort your list just call Collections.sort(list);; however this list will contain all the data so modify the code to group the data by the employee name and have a list per each employee
For your purposes, it sounds like you really want an object to represent a Person, who has some amount of Experience. Since your input source has the data denormalized, easiest way to do that is to populate a Map<String,Person> as you parse your file:
scanner.useDelimiter(",|\\n");
while (scanner.hasNext()) {
String line = scanner.next();
String[] fields = line.split(",");
String name = fields[0];
Person person = map.get(name);
if (person == null) {
person = new Person(name);
map.put(name, person);
}
person.addJob(fields[1], Integer.parseInt(fields[2]));
}
List<Person> people = new ArrayList<Person>(map.values());
After this process, you'll end up with a List of People, in no particular order. For each Person, since you want to keep their job's in order sorted by experience, you'd need to implement Person.addJob in such a way as to keep it ordered. A SortedSet is a really nice way to do this, but you can't insert duplicates, and since you want to sort by experience, and a person could've been at two jobs the same amount of time you need to use an alternate approach. There's several ways to do this, but without making assumptions about your data I'd suggest keeping a sorted List of Job objects:
class Person {
private final List<Job> jobs = new LinkedList<Job>();
// Constructor, etc...
public void addJob(String companyName, int yearsOfExperience) {
Job newJob = new Job(companyName, yearsOfExperience);
int insertionIndex = Collections.binarySearch(jobs, newJob);
if (insertionIndex < 0) {
insertionIndex = (-(insertionIndex) - 1);
}
jobs.add(insertionIndex, newJob);
}
}
and finally, a Job should implement Comparable<Job>, so that you can look it up:
class Job implements Comparable<Job> {
private final String companyName;
private final int yearsOfExperience;
// Constructor, etc...
public int compareTo(Job otherJob) {
return Integer.compare(yearsOfExperience,otherJob.yearsOfExperience);
}
}
That bit of trickery in Person.addJob will keep the List always sorted by the 'natural order' of Job. (see Collections.binarySearch).

Categories