Java, sort and display data from txt file - java

i'm new with java and have some trouble with one task.
i have txt file which looks like this:
John Doe,01-01-1980,Development,Senior Developer
Susan Smith,07-12-1983,Development,Head of Development
Ane Key,06-06-1989,BA,Junior Analyst
Nina Simone,21-09-1979,BA,Head of BA
Tom Popa,23-02-1982,Development,Developer
Tyrion Lannyster,17-03-1988,BA,Analyst
and i want to to sort it by departments.
for example:
Members are :
[Employee Full Name] - [Employee Age] - [Employee Position] - [Employee Salary(default value x)]
Deparment : Development
Members are :
Susan Smith ......
John Doe ......
Tom Popa ......
Department : BA
Members are :
Nina Simone .......
Ane Key ...........
Tyrion Lannyster ........
at first read file and made 2d array but can't continue how to correctly sort it.
public static void main(String[] args) {
String csvFile = "C:\\Employees.txt";
BufferedReader br = null;
String line = "";
String SplitBy = ",";
String myArray[][] = new String[6][5];
int row = 0;
try {
br = new BufferedReader(new FileReader(csvFile));
while ((line = br.readLine()) != null) {
String nums[] = line.split(SplitBy);
for (int col = 0; col < nums.length; col++){
String n =nums[col];
myArray[row][col] = n;
// System.out.println(n);
}
row++;
}
}
catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

Providing the code solution here would not help you learn it. But I can give you hints on how to proceed. Using array is not really recommended.
The easy, but dirty way -
Instead of two dimensional array, use a TreeMap<String, String[]> where key is the department concatenated with name and value is the one dimensional array of the individual's details. As we're using TreeMap, the result is naturally sorted based on Department followed by Name of the person. Loop through the entrySet and print all the results.
Right way -
Define new object Person with all the members needed. Implement Comparable interface. Read all the input data, populate the same in Person object, add each such objects in an ArrayList and use Collections API's sort method to sort all the objects. Alternatively you can adapt the Comparator way.

The Java Collections APIallows you to Sort as well as util.Arrays.
You will need the arrays methods for you code, but consider moving to some sort of Collection. Perhaps a List to start with.

The easiest way would put the contents of the lines in Java Beans and then sort them using sort.
public User {
private String name;
// ... all the fields with getters and setters
}
Then adapt your code to something like this:
// create a nice List for the users.
List<User> userList = new ArrayList<>();
while ((line = br.readLine()) != null) {
User user = new User();
String nums[] = line.split(SplitBy);
user.setName(nums[0]);
// create nice method to convert String to Date
user.setDate(convertStringToDate(nums[1]));
// add the user to the list
userList.add(user);
}
// Then finally sort the data according to the desired field.
Arrays.sort(userList, (a,b) -> a.name.compareTo(b.name));

Related

Adding new key-value pair gets other keys' values replaced in HashMap

So, I have a HashMap<String,ArrayList> that stores an arraylist per String. But when I add another pair with new value of ArrayList, the other key values are being replaced. Hence, all the values for the different keys are getting the same.
public class Reports{
private ArrayList<Resource> resourceList;
private HashMap<String,ArrayList<Resource>> consolidatedAttendance = new HashMap<String,ArrayList<Resource>>();
public void readReport(String reportFile){
//initialized with resources from config file
ArrayList<Resource> repResourceList = new ArrayList<Resource>(getResourceList());
try (BufferedReader br = new BufferedReader(new FileReader(reportFile))) {
String line;
line = br.readLine(); // disregards first line (columns)
while ((line = br.readLine()) != null) {
if(line.length()==0){
break;
}
//store each resource status in resourceList
String[] values = line.split(",");
String resourceName = values[1], resourceStatus = values[2];
int resourceIndex = indexOfResource(resourceList, resourceName);
// to add validation
if(resourceIndex!=-1){
repResourceList.get(resourceIndex).setStatus(resourceStatus);
}
}
}catch(IOException e){
e.printStackTrace();
}
//get Date
String reportFilename = reportFile.substring(0, reportFile.indexOf("."));
String strDate = reportFilename.substring(reportFilename.length()-9);
consolidateRecords(strDate, new ArrayList<Resource>(repResourceList));
}
public void consolidateRecords(String strDate, ArrayList<Resource> repResourceList){
//consolidate records in hashmap
consolidatedAttendance.put(strDate, repResourceList);
// test print
for (String key: consolidatedAttendance.keySet()){
ArrayList<Resource> resources = consolidatedAttendance.get(key);
for(Resource resource: resources){
System.out.println(key+": "+resource.getNickname()+" "+resource.getEid()+" "+resource.getStatus());
}
}
}
}
So the output for the map when it is printed is:
First key added:
"21-Dec-20": John Working
"21-Dec-20": Alice Working
"21-Dec-20": Jess Working
For second key, there's difference in the list. But,
When second key is added (after put() method), the first key's values have been replaced.
"21-Dec-20": John SL
"21-Dec-20": Alice Working
"21-Dec-20": Jess SL
"28-Dec-20": John SL
"28-Dec-20": Alice Working
"28-Dec-20": Jess SL
The values of your Map are Lists whose elements are the same as the elements of the List returned by getResourceList(). The fact that you are creating a copy of that List (twice), doesn't change that.
If each call to getResourceList() returns a List containing the same instances, all the keys in your Map will be associated with different Lists that contain the same instances.

Is there a way loop through 2 arrays and print the element of array 1 if it contains the substring of any element from array 2?

The problem I am trying to solve is how to read lines from a text file and add it to an array. Then sort each element from this new array by the date that is also in each element. I will explain so its easier to understand but will explain what I am doing.
My text file (First column is name, second is Date of birth and last is the date the person died):
sarah jones,1966-12-02,2018-12-04
matt smith,1983-02-03,2020-03-02
john smith,1967-03-04,2017-04-04
I want to sort this file and output it to another file (testing by printing to console at the moment) by sorting it by the date the person died. A way I thought of doing this is to read each line and pass it to an array. Then read each element within the array, split it and then save the date the person died to another array. Then sort the array that has the death dates, loop through both arrays by seeing if the first element of the death date array matches the first element of the first line in the text file, if so then write it to another file. If not then go to the next line.
For example
BufferedReader reader = new BufferedReader(new FileReader("input_text.txt"));
PrintWriter outputStream = new PrintWriter(new FileWriter("output.txt",true));
ArrayList<String> lines = new ArrayList<String>();
ArrayList<String> substr_date = new ArrayList<String>();
String currentline = reader.readLine();
while(currentline !=null){
String a_line[] = currentline.split(",");
substr_date.add(a_line[2])
lines.add(currentline);
currentline = reader.readLine();
}
Collections.sort(substr_date);
for(String date : substr_date){
for(String line : lines){
if(line.contains(date)){
System.out.println(line);
}
}
}
I expect the output to be:
john smith,1967-03-04,2017-04-04
sarah jones,1966-12-02,2018-12-04
matt smith,1983-02-03,2020-03-02
The results are initially in order but then some lines are repeated multiple times and then the whole text file in repeated to the console and becomes a mess. I am not sure how to go about doing this. I am new to java and not sure if I asked this question properly either so if you need any more info please ask.
I would create class for objects which you can insert into a list and then define a comparator on this class which you can use to sort.
Here is an example of the class you could define:
static class DeceasedPerson {
String name;
LocalDate birthDate;
LocalDate deathDate;
DeceasedPerson(String name, LocalDate birthDate, LocalDate deathDate) {
this.name = name;
this.birthDate = birthDate;
this.deathDate = deathDate;
}
#Override
public String toString() {
return name + ", " + birthDate + ", " + deathDate;
}
}
Then you could simply load objects based on this class into a list which you sort using a comparator. Here is some sample code you can run with the class defined above:
public static void main(String[] args) {
String input =
"matt smith,1983-02-03,2020-03-02\n" +
"sarah jones,1966-12-02,2018-12-04\n" +
"john smith,1967-03-04,2017-04-04\n";
List<DeceasedPerson> deceasedPersonList = new ArrayList<>();
try (Scanner scanner = new Scanner(input)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
String[] array = line.split(",");
DeceasedPerson deceasedPerson = new DeceasedPerson(array[0],
LocalDate.parse(array[1]), LocalDate.parse(array[2]));
deceasedPersonList.add(deceasedPerson);
}
}
deceasedPersonList.sort(Comparator.comparing(o -> o.deathDate));
deceasedPersonList.forEach(System.out::println);
}
If you run the code above using the DeceasedPerson class you should see on the console the following output:
john smith, 1967-03-04, 2017-04-04
sarah jones, 1966-12-02, 2018-12-04
matt smith, 1983-02-03, 2020-03-02
You could actually also use a TreeSet instead of a List in the main method above and achieve the same results. Here is a move concise alternative:
public static void main(String[] args) {
String input =
"matt smith,1983-02-03,2020-03-02\n" +
"sarah jones,1966-12-02,2018-12-04\n" +
"john smith,1967-03-04,2017-04-04\n";
Set<DeceasedPerson> deceasedPersonList = new TreeSet<>(Comparator.comparing(o -> o.deathDate));
try (Scanner scanner = new Scanner(input)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
String[] array = line.split(",");
DeceasedPerson deceasedPerson = new DeceasedPerson(array[0],
LocalDate.parse(array[1]), LocalDate.parse(array[2]));
deceasedPersonList.add(deceasedPerson);
}
}
deceasedPersonList.forEach(System.out::println);
}
The way you are doing is a long shot. You can do this in much simpler way. You could pass a comparator to the Collections.sort() method like this.
Collections.sort(substr_date, new Comparator<String>{
#Override
public int compare(String str1, String str2){
String dd1 = str1.split(",")[2];
String dd2 = str2.split(",")[2];
return dd1.compareTo(dd2);
}
});
Comparing dates like this, though, is not a good approach. You should convert the date string to LocalDateTime and then use isBefore() or isAfter() to compare them. For ex,
public int compare(String str1, String str2){
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd")
LocalDateTime d1 = LocalDateTime.parse(str1.split(",")[2],format);
LocalDateTime d2 = LocalDateTime.parse(str2.split(",")[2],format);
return d1.isBefore(d2)?-1:(d1.isAfter(d2)?1:0);
}

Sort ArrayList of countries by name, habitants and size

I want to create three methods which I can use to sort an ArrayList, which reads a list of countries from a text file by the name of the country (alphabetically), the amount of habitants and the size of the country. I know how to sort them by the names but I am lost on how to sort by habitants and sizes.
This is how the text file is structured; name of country, habitants, size and capital.
Belgien 10584534 30528 Bryssel
Bosnien 4590310 51129 Sarajevo
Cypern 854000 9250 Nicosia
Serbien 7276195 77474 Belgrad
I've made a method which reads the file and sorts it with Collections.sort(), but as stated earlier I dont know how to even begin on the other two methods.
My code so far:
public class Land {
static boolean valid = true;
public static boolean sortNames() {
File file = new File("europa.txt");
ArrayList<String> list = new ArrayList<String>();
try{
Scanner scan = new Scanner(file);
while(scan.hasNextLine()){
list.add(scan.nextLine());
}
scan.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();}
ListIterator iterator = list.listIterator();
Collections.sort(list);
System.out.println("Country: Inhabitants: Size: Capital: \n");
for (String element : list) {
System.out.println(element);
}
return valid;
}
public static void main(String[] args) {
System.out.print("\n" + sortNames());
}
}
The code as it is now prints:
Country: Inhabitants: Size: Capital:
Albanien 3581655 28748 Tirana
Belgien 10584534 30528 Bryssel
Bosnien 4590310 51129 Sarajevo
Don't just read and store the lines as a whole, but split them up in fields and create decent 'Country' objects. Store these objects in a List. You can use the Collections.sort(list, comparator) to sort your countries based on different implemetations based on the fields of your country objects.
public static boolean sortNames() {
File file = new File("europa.txt");
ArrayList<Country> list = new ArrayList<Country>();
try {
Scanner scan = new Scanner(file);
while(scan.hasNextLine()){
String line = scan.nextLine();
Country country = new Country();
// Split the line and fill the country object
list.add(country);
}
scan.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
Collections.sort(list, new Comparator<Country>(){
#Override
public int compare(Country c1, Country c2) {
return c1.getName().compareTo(c2.getName());
}
});
// You can create different comparators and sort based on inhabitants, capital, or even a combination of fields...
System.out.println("Country: Inhabitants: Size: Capital: \n");
for (Country element : list) {
System.out.println(element.getName() + ", " + element.getInhabitants() /*etc*/);
}
return valid;
}
public class Country {
private String name;
private int inhabitants;
private int size;
private String capital;
// constructor
// getters and setters
}
For java 8 and above:
You should split the rows up and create Country objects with fields:
nameOfCountry, habitants, size, capital
After that you could use the List.sort() method as follows:
list.sort(Comparator.comparing(Country::getNameOfCountry)
.thenComparing(Country::getHabitants)
.thenComparing(Country::getSize));

Getting the highest column value from csv file and storing it into arraylist

I'm trying to store into arraylistONE the Sub Name of Name that has the highest admin value.
In this case,
All-Purpose Flour it is 1 3/4 cups all-purpose flour
Baking Powder it is 1/4 teaspoon baking soda and 1/2 cup of plain
Baking Soda it is 8 teaspoons of baking powder
If a Name only has 0 admin values it should be,
Brewed Coffee it should always store the first value in the file which is 1 cup brewed coffee
And for the rest of the data that has lesser admin value, they are stored into arraylistTWO.
I'm stuck in reading the csv file and i don't know how to store into arraylistONE the Sub Name of Name that has the highest admin value and for the rest of the data that has lesser admin value, i don't know how to store into arraylistTWO.
This is the work i've done so far:
try {
br = new BufferedReader (new FileReader ("/sdcard/TABLE_BF.csv"));
while ((sCurrentline = br.readLine ()) != null) {
subIng.add(sCurrentline.split (","));
}
arrSubIng = new String[subIng.size ()][];
subIng.toArray (arrSubIng);
} catch (IOException e) {
e.printStackTrace ();
}
First of all I think it makes sense to create a simple class that holds the data since it will be easier to filter and sort using objects rather than arrays of values.
public class Ingredient {
String name;
String subName;
int status;
int admin;
public Ingredient(String name, String subName, String status, String admin) {
this.name = name;
this.subName = subName;
this.status = Integer.valueOf(status);
this.admin = Integer.valueOf(admin);
}
public String getName() {
return name;
}
public int getAdmin() {
return admin;
}
//more get and set methods here. I have only included what is needed for my answer
}
Then you read and create a list of Ingredient objects.
List<Ingredient> data = new ArrayList<>();
try {
String sCurrentline = null;
BufferedReader br = new BufferedReader(new FileReader("/sdcard/MAIN_BF.csv"));
while ((sCurrentline = br.readLine()) != null) {
String[] arr = sCurrentline.split(",");
Ingredient ingredient = new Ingredient(arr[0], arr[1], arr[2], arr[3]);
data.add(ingredient);
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
Then we group the list by name into a Map
Map<String, List<Ingredient>> ingredientsByName = data.stream().collect(Collectors.groupingBy(Ingredient::getName));
And loop over that map to find the max admin value for each ingredient and add them to the correct list
List<Ingredient> main = new ArrayList<>();
List<Ingredient> other = new ArrayList<>();
//Sort on `admin` in descending order
Comparator<Ingredient> compartor = Comparator.comparing(Ingredient:: getAdmin, (i1, i2) -> {
if (i2 > i1) {
return -1;
} else if (i2 < i1) {
return 1;
}
return 0;
});
//Go through each list (ingredient) and find the one with max `admin` value
//and add it to the `main` list then add the rest to `other`
ingredientsByName.forEach( (k, group) -> {
Ingredient max = group.stream().max(compartor).get();
if (max.getAdmin() == 0) {
max = group.get(0);
}
main.add(max);
group.remove(max);
other.addAll(group);
});
I would load the entire contents of the file into memory and store it in a java.util.List<String>. Then you could sort the List by Name and admin. Then just iterate through the List. Whenever you hit a different Name, you know that its associated admin value is the largest. So you add that to your first ArrayList and all the others to your second ArrayList.

Java - Specific .contain() logic

I'm reading multiple string and adding them to Vector which looks like this.
public void readCode(){
BufferedReader abc;
try {
abc = new BufferedReader(new FileReader("code.txt"));
String line;
while((line = abc.readLine()) != null) {
lines.add(line);
}
abc.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
for(int i = 0;i<lines.size();i++){
String x=lines.get(i);
String[] split = x.split("#");
vkCode.add(split[0]);
vkName.add(split[1]);
}
}
And then i'm using this code to find the item code of certain item name.
String cmpre="";
banding = sc.nextLine();
int target = -1;
for(int p = 0;p<vkName.size();p++){
if(vkName.get(p).toString().toLowerCase().contains(cmpre)){
target=p;
break;
}
}
if(target==-1){
System.out.println("Item does not exist!");
}
else{
System.out.println("Item Code is : "+vkCode.get(target));
}
So far the code works just fine , but there is a problem.
Let say the list of item looks like this.
Edit requested:
Data Sample
1213112#PT ABC Syariah Tbk
1212112#PT ABC Tbk
1241312#PT ABC Central Tbk
Case 1:
If we try to find ABC the expected result is PT ABC Tbk ID which is 1212112 but due to my code it will result in PT ABC Syariah Tbk ID instead
Case 2:
If we try to find Syariah ABC it will not return any code at all. Due to the textfile having ABC Syariah which is a problem too.
First generate a collection of fuzzy matches using .contains(). Then, from that collection, generate a second collection of exact matches using .equals(). Then return the first exact match if there is one, else return the first fuzzy match if there is one, else null.

Categories