I have a list in java that contains lines of string id;city;date;days;price;vehicle. I need to sort all of it by date.(it's from a csv file that I read)
My list:
List <Ticket> list = new LinkedList<Ticket>();
And the way it is defined:
class Ticket {
int id;
String city;
String date;
int days;
float price;
String vehicle;
Ticket(int i, String c, String y, int d, float p, String v) {
id = i;
city = c;
date = y;
days = d;
price = p;
vehicle = v;
}
I was trying bubble sort but I have no clue how to compare dates and all the examples I found had ArrayList or were comparing small amounts of dates. I'm sorry if this is a bad question I just don't know how to apply everything I found to my situation.
You can do this with Comparator interface. I prefer to convert the string into date first.
For dd/MM/yyyy (01/01/1970) pattern example (without conversion):
List<Ticket> list = new LinkedList<Ticket>();
... //fill the list.
Collections.sort(list, new Comparator<Ticket>() {
public int compare(Ticket t1, Ticket t2) {
String[] dateParts1 = t1.date.split("/");
String[] dateParts2 = t2.date.split("/");
int yearResult = dateParts1[2].compareTo(dateParts2[2]);
if (yearResult != 0) {
return yearResult;
}
int monthResult = dateParts1[1].compareTo(dateParts2[1]);
if (monthResult != 0) {
return monthResult;
}
int dayResult = dateParts1[0].compareTo(dateParts2[0]);
if (dayResult != 0) {
return dayResult;
}
return 0;
}
});
or (with conversion):
List<Ticket> list = new LinkedList<Ticket>();
... //fill the list.
Collections.sort(list2, new Comparator<Ticket>() {
public int compare(Ticket t1, Ticket t2) {
String pattern = "dd/MM/yyyy";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
try {
Date date1 = simpleDateFormat.parse(t1.date);
Date date2 = simpleDateFormat.parse(t2.date);
return date1.compareTo(date2);
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
}
});
Also, you can do same thing in class with Comparable interface.
public class Ticket **implements Comparable<Ticket>** {
int id;
String city;
String date;
int days;
float price;
String vehicle;
Ticket(int i, String c, String y, int d, float p, String v) {
id = i;
city = c;
date = y;
days = d;
price = p;
vehicle = v;
}
**#Override
public int compareTo(Ticket o) {
String[] dateParts1 = this.date.split("/");
String[] dateParts2 = o.date.split("/");
int yearResult = dateParts1[2].compareTo(dateParts2[2]);
if (yearResult != 0) {
return yearResult;
}
int monthResult = dateParts1[1].compareTo(dateParts2[1]);
if (monthResult != 0) {
return monthResult;
}
int dayResult = dateParts1[0].compareTo(dateParts2[0]);
if (dayResult != 0) {
return dayResult;
}
return 0;
}**
}
Then:
List<Ticket> list = new LinkedList<Ticket>();
... //fill the list.
Collections.sort(list);
You can parse the date String to a date object like LocalDateTime or Instant and etc' (depending on your use case).
I randomly picked LocalDateTime for this example.
Then you can do:
tickets.add(new Ticket(1, "dsa", LocalDateTime.now().plusSeconds(5), 6, 5, "rew"));
tickets.add(new Ticket(0, "dsa", LocalDateTime.now(), 6, 5, "rew"));
List<Ticket> sortedTicketsByDate = tickets.stream()
.sorted(Comparator.comparing(t -> t.date)) // comparing by date
.collect(Collectors.toList());
System.out.println(sortedTicketsByDate);
Output:
[
Ticket(id=0, city=dsa, date=2021-05-02T23:46:03.214, days=6, price=5.0, vehicle=rew),
Ticket(id=1, city=dsa, date=2021-05-02T23:46:08.197, days=6, price=5.0, vehicle=rew)
]
Here is another clean version using java records (new since JDK 16) which is recommended for plain java objects (pojos) that store data.
Read more info in this article : https://www.baeldung.com/java-record-keyword
You implement the Comparable interface based on date and Collections.Sort() can sort your ArrayList based on that.
import java.util.ArrayList;
import java.util.Collections;
record Ticket(int id,String city,String date,int days,float price,String vehicle) implements Comparable<Ticket>{
public int compareTo(Ticket ticket){
return this.date.compareTo(ticket.date);
}
}
public class Main{
public static void main(String[] args) {
Ticket ticket1 = new Ticket(1,"New York","2021-05-03",10,110.30f,"Ferrari");
Ticket ticket2 = new Ticket(2,"Miami","2021-05-02",9,120.50f,"Porche");
Ticket ticket3 = new Ticket(3,"Los Angeles","2021-05-01",10,150.50f,"Mercedes");
var list = new ArrayList<Ticket>();
list.add(ticket1);
list.add(ticket2);
list.add(ticket3);
System.out.println("The List before sorting:\n");
list.forEach(System.out::println);
Collections.sort(list);
System.out.println("\nThe List After sorting:\n");
list.forEach(System.out::println);
}
}
Related
I need to show a list sorted by countries with the minimum days to reach 50,000 cases in the .csv file. The countries are displaying by each day in each line, so I have to read each line to figure it out how many days. In the end it should print the number of countries that achieved 50,000 cases in the minimum days, in ascending order.
Spain Beginning
Spain Ending
So in this case it should show 84 days to reach 50000 cases.
In this code if it passes 50000 cases, it won't enter the while loop, so I guess I'm doing something wrong. And I'm not sure if in this one I'm giving the country the minimum number or if I'm just giving the line of the day.
// Constructor for class Country
public Country(String isoCode, String continent, String location, LocalDate date, int totalCases, int newCases, int totalDeaths, int newDeaths, int newTests, int totalTests, int population,
double older65, double cardiDeathRate, double diabetesPrevalence, double femaleSmokers, double maleSmokers, double numBeds, double lifeExpectancy) {
this.isoCode = isoCode;
this.continent = continent;
this.location = location;
this.date = date;
this.totalCases = totalCases;
this.newCases = newCases;
this.totalDeaths = totalDeaths;
this.newDeaths = newDeaths;
this.newTests = newTests;
this.totalTests = totalTests;
this.population = population;
this.older65 = older65;
this.cardiDeathRate = cardiDeathRate;
this.diabetesPrevalence = diabetesPrevalence;
this.femaleSmokers = femaleSmokers;
this.maleSmokers = maleSmokers;
this.numBeds = numBeds;
this.lifeExpectancy = lifeExpectancy;
}
This is the loader code:
public boolean load(String filename) {
p = new ArrayList<>();
try{
Files.lines(Paths.get(filename)).skip(1).forEach(p -> loadLine(p));
} catch (Exception e) {
return false;
}
return true;
}
private void loadLine(String line) {
String [] data = line.split(",");
p.add(new Country(data[0],
data[1],
data[2],
LocalDate.parse(data[3),
Integer.parseInt(data[4]),
Integer.parseInt(data[5]),
Integer.parseInt(data[6]),
Integer.parseInt(data[7]),
Integer.parseInt(data[8]),
Integer.parseInt(data[9]),
Integer.parseInt(data[10]),
Integer.parseInt(data[11]),
Double.parseDouble(data[12]),
Double.parseDouble(data[13]),
Double.parseDouble(data[14]),
Double.parseDouble(data[15]),
Double.parseDouble(data[16]),
Double.parseDouble(data[17])));
}
And this is the sort one:
public List<Country> sortedByMinDays(Country p1, Country p2) {
int min=0;
List<Country> lp = new ArrayList<>(p);
while(p1.getIsoCode()==p2.getIsoCode() && p2.getTotalCases()<=50000){
min=min + 1;
p2.setMinDays(min);
}
for (int n=0; n<lp.size(); n++){
if (p2.getMinDays()<p1.getMinDays()){
int aux = p1.getMinDays();
p2.setMinDays(p1.getMinDays());
p1.setMinDays(aux);
}
}
return sortedByMinDays(p1, p2);
}
I came across a problem where one needs to check for rows in Array1 that are not in Array2 and append it at the end of Array2 in Java. The rows that are common with regard to the first column i.e. name can be skipped. In the below example, the rows in firstarray with "Nick" and "Bruce" should be appended at the end of secondarray.
I have edited the arrays again slightly to get more clarity.
String firstarray[][] = {
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"},
{"Nick","09-06-1974","History","Johanesburg"},
{"Bruce","13-08-1975","Philosophy","Seattle"}};
String secondarray[][] = {
{"Adam","01-Dec-1980","Commerce","New York"},
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"}};
The solution should be like:
secondarray[][]:
{"Adam","01-Dec-1980","Commerce","New York"},
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"},
{"Nick","09-06-1974","History","Johanesburg"},
{"Bruce","13-08-1975","Philosophy","Seattle"}}
Collect the names of the second array to a set, iterate over your first array and filter out those elements which are in the set and collect the result in a third array (or any other collection). Append this collection to your second array.
public static void main(String[] args){
String firstarray[][] = {
{"Adam","01-Dec-1980","Commerce","Kansas"},
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"},
{"Nick","09-06-1974","History","Johanesburg"},
{"Bruce","13-08-1975","Philosophy","Seattle"}};
String secondarray[][] = {
{"Adam","01-Dec-1980","Commerce","Kansas"},
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"},
{"Sujay Muramalla","08-Jan-1985","Arts","London"}};
//collect names of second array to set
Set<String> secondSet = Arrays.stream(secondarray).map(e -> e[0]).collect(Collectors.toSet());
//stream over your first array and keep only those which are not in the above set
String[][] third = Arrays.stream(firstarray)
.filter(e -> !secondSet.contains(e[0]))
.toArray(String[][]::new);
//stream over second and delta (third array) and collect to a result array
String[][] result = Stream.concat(Arrays.stream(secondarray), Arrays.stream(third))
.toArray(String[][]::new);
//output
Arrays.stream(result).forEach(e ->{
System.out.println(Arrays.toString(e));
});
}
You should not be using arrays for this. Much better to use libraries already doing the job.
Even if the data you receive is already that way, you can converted first to a Map<String, Person> it will be more efficient, and readable code.
With arrays or many solutions not using some hashing system, you end up with exponential complexity O(n2), so not efficient.
Convert at least secondarray
Map<String, Person> secondMap = new HashMap();
for(String [] row : secondarray){
secondMap.put(row[0], new Person(row[0], row[1], row[2], row[3]));
}
Then put in the map if not already there
for(String[] row : firstarray){
if(!secondMap.containsKey(row[0])){
secondMap.put(row[0], new Person(row[0], row[1], row[2], row[3]));
}
}
Where Person class could be simply defined as
private static class Person{
public Person(String name, String birth, String area, String city){
this.name = name;
this.birth = birth;
this.area = area;
this.city = city;
}
String name;
String birth;
String area;
String city;
}
if you want check more than the first element of the array you can use nopens solution and replace e[0] with Arrays.toString(e).
A cleaner way if this is possible for you, is to use a list with a object and use a id for checking equals or override the hashcode function of the customer object.
You can also check for name and birth like that:
class Customer {
private String name;
private String birth;
private String type;
private String location;
public Customer(String name, String birth, String type, String location) {
this.name = name;
this.birth = birth;
this.type = type;
this.location = location;
}
#Override
public String toString() {
return "Customer [name=" + name + ", birth=" + birth + ", type=" + type + ", location=" + location + "]";
}
}
List<Customer> firstList = new ArrayList<Customer>();
firstList.add(new Customer("Adam", "01-Dec-1980", "Commerce", "Kansas"));
firstList.add(new Customer("John", "04-Feb-1982", "Economics", "Leeds"));
firstList.add(new Customer("Mathias", "08-Jan-1985", "Arts", "London"));
firstList.add(new Customer("Nick", "09-06-1974", "History", "Johanesburg"));
firstList.add(new Customer("Bruce", "13-08-1975", "Philosophy", "Seattle"));
List<Customer> secondList = new ArrayList<Customer>();
secondList.add(new Customer("Adam", "01-Dec-1980", "Commerce", "Kansas"));
secondList.add(new Customer("John", "04-Feb-1982", "Economics", "Leeds"));
secondList.add(new Customer("Mathias", "08-Jan-1985", "Arts", "London"));
for (Customer customer : firstList) {
if (containsNameAndBirth(secondList, customer) == false) {
secondList.add(customer);
}
}
for (Customer customer : secondList) {
System.out.println(customer);
}
}
public static boolean containsNameAndBirth(final List<Customer> list, final Customer customer) {
return list.stream().filter(o -> o.name.equals(customer.name) && o.birth.equals(customer.birth)).findFirst()
.isPresent();
}
EDIT 1 - Using Custom Class
I suggest you to always use List over Array.
import java.time.*;
import java.util.*;
import java.util.stream.Collectors;
public class Main {
static class Person {
public String name;
public String birthDate;
public String field;
public String city;
public static Person fromArray(String[] data) {
Person p = new Person();
if (data.length == 4) {
p.name = data[0];
p.birthDate = data[1];
p.field = data[2];
p.city = data[3];
} else {
// Handle me
}
return p;
}
#Override
public String toString() {
return new StringBuilder("[").append(name)
.append(",").append(birthDate)
.append("] learns ").append(field)
.append(" at ").append(city).toString();
}
}
public static void main(String[] args) {
String firstArray[][] = {
{"Adam","01-Dec-1980","Commerce","Kansas"},
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"},
{"Nick","09-06-1974","History","Johanesburg"},
{"Bruce","13-08-1975","Philosophy","Seattle"}};
String secondArray[][] = {
{"Adam","01-Dec-1980","Commerce","Kansas"},
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"}};
List<Person> finalList = getFinalList(firstArray, secondArray);
// Display
System.out.println(finalList);
}
public static List<Person> getFinalList(String[][] arr1, String[][] arr2) {
// First cast to Lists of persons
List<Person> firstList = Arrays.asList(arr1).stream().map(Person::fromArray).collect(Collectors.toList());
List<Person> secondList = Arrays.asList(arr2).stream().map(Person::fromArray).collect(Collectors.toList());
// Get names in secondList
Set<String> existingNames = secondList.stream().map(p -> p.name).collect(Collectors.toSet());
System.out.println("Names: "+ existingNames);
firstList.forEach(person -> {
if (! existingNames.contains(person.name)) {
secondList.add(person);
}
});
return secondList;
}
}
I upvoted nopens solutions cause it is nice one
Here another that uses maps and makes use of a logic of skipping common keys using removeAll on the keySet of the map, which was a functional method existing befor Java turned "more" functional
static public <T> Map<T,T[]> arrayToMap(T[][] array, int i) {
return Arrays.stream(array).collect(Collectors.toMap(e -> e[i], e -> e));
}
public static void main(String[] args){
String firstarray[][] = {
{"Adam","01-Dec-1980","Commerce","Kansas"},
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"},
{"Nick","09-06-1974","History","Johanesburg"},
{"Bruce","13-08-1975","Philosophy","Seattle"}};
String secondarray[][] = {
{"Adam","01-Dec-1980","Commerce","Kansas"},
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"},
{"Sujay Muramalla","08-Jan-1985","Arts","London"}};
Map<String,String[]> firstMap = arrayToMap(firstarray, 0);
Map<String,String[]> secondMap = arrayToMap(secondarray, 0);
secondMap.keySet().removeAll(firstMap.keySet());
firstMap.putAll(secondMap);
String[][] result = firstMap.values().stream().toArray(String[][]::new);
//output
Arrays.stream(result).forEach(e ->{
System.out.println(Arrays.toString(e));
});
}
sidenote: in arrayToMap you can choose which column you use as key.
And the logic could be even reduced to this 3 lines:
Map<String,String[]> firstMap = arrayToMap(firstarray, 0);
firstMap.putAll(arrayToMap(secondarray, 0));
String[][] result = firstMap.values().stream().toArray(String[][]::new);
since inserting a value with the same key overwrites the existing one and you get the same if the values are the same in case of equal keys.
A simple an efficient way to do it (if you don't care about ordering) is the following:
Time complexity: O(nlog(n))
Space complexity: O(n+m)
import java.util.Arrays;
public class Main {
public static void main(String ... args) {
String firstarray[][] = {
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"},
{"Nick","09-06-1974","History","Johanesburg"},
{"Bruce","13-08-1975","Philosophy","Seattle"}};
String secondarray[][] = {
{"Adam","01-Dec-1980","Commerce","Kansas"},
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"}};
String result [][] = new String[firstarray.length
+ secondarray.length][firstarray[0].length];
// sort firstarray
java.util.Arrays.sort(firstarray, new java.util.Comparator<String[]>() {
public int compare(String [] a, String[] b) {
return a[0].compareTo(b[0]);
}
});
//sort secondarray
java.util.Arrays.sort(secondarray, new java.util.Comparator<String[]>() {
public int compare(String [] a, String[] b) {
return a[0].compareTo(b[0]);
}
});
int i = 0, j=0, k=0, cmp ;
for ( ;i < secondarray.length && j< firstarray.length;) {
cmp = firstarray[i][0].compareTo(secondarray[j][0]);
if(cmp ==0) {
System.arraycopy(firstarray[i], 0, result[k++], 0, 4);
i++; j++;
}else if( cmp <0){
System.arraycopy(firstarray[i], 0, result[k++], 0, 4);
i++;
} else {
System.arraycopy(secondarray[j], 0, result[k++], 0, 4);
j++;
}
}
// copy the remaining if any from firstarray to the result
for (; i < firstarray.length; i++) {
System.arraycopy(firstarray[i], 0, result[k++], 0, 4);
}
// copy the remaining if any from secondarray to the result
for (; j < secondarray.length; j++) {
System.arraycopy(secondarray[j], 0, result[k++], 0, 4);
}
//resize it
secondarray = Arrays.copyOf(result, k);
// just print the secondarray
for (int x = 0; x < secondarray.length; x++) {
for (int y = 0; y < 4; y++) {
System.out.print(secondarray[x][y] + ",");
}
System.out.println("");
}
}
}
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
This is my complete program
public class Client {
public static void main(String args[]) {
ArrayList < Student > studentsList = new ArrayList <> ();
Student std1 = new Student("Ram","01-01-1981","1203");
Student std2 = new Student("Raj","01-01-1981","1204");
Student std3 = new Student("Hanish","01-01-1981","403");
Student std4 = new Student("Hanish","01-01-1981","");
studentsList.add(std1);
studentsList.add(std2);
studentsList.add(std3);
studentsList.add(std4);
Collections.sort(studentsList);
System.out.println(studentsList);
}
}
When i print i see that the GL Number is not coming in acsending Order
The problem is that you are comparing the String GlNumber, not the number it represents. You state in the code that GLNumber is alphanumeric, so I think it's fair to say that your comparator works to spec.
"1204" < "403"
1204 > 403
On a side note: why store studentDOJ as String too? Seems like it should be java.time.LocalDate.
This happens because your glNumber is in String and You want numerical ascending.
You can understand the problem using the following examples
Sample 1
List stringList = Arrays.asList("1","2","10");
Collections.sort(stringList);
System.out.println(stringList);
// Returns [1, 10, 2]
Sample 2
List numberList = Arrays.asList(1,2,10);
Collections.sort(numberList);
System.out.println(numberList);
// Returns [1, 2, 10]
Now, the solution to your problem. Try below compareTo(...)
#Override
public int compareTo(Student other) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
return Comparator.comparing((Student student) -> LocalDate.parse(student.getStudentDOJ(), formatter)).reversed()
.thenComparingLong(student -> student.getGlNumber().length() == 0 ? 0 : Long.valueOf(student.getGlNumber()))
.compare(this, other);
}
create studentDateComparator which implements Comparator as follows:
#Override
public int compare(Student a, Student b) {
// ascending
// int r = a.getStudentDOJ().compareTo(b.getStudentDOJ());
// decending
int r = b.getStudentDOJ().compareTo(a.getStudentDOJ());
if (r == 0) {
r = comparison(a, b);
}
return r;
}
public int comparison(Student a, Student b) {
String s1 = a.getGlNumber();
String s2 = b.getGlNumber();
String[] pt1 = s1.split("((?<=[a-z])(?=[0-9]))|((?<=[0-9])(?=[a-z]))");
String[] pt2 = s2.split("((?<=[a-z])(?=[0-9]))|((?<=[0-9])(?=[a-z]))");
// pt1 and pt2 arrays will have the string split in alphabets and numbers
int i = 0;
if (Arrays.equals(pt1, pt2))
return 0;
else {
for (i = 0; i < Math.min(pt1.length, pt2.length); i++)
if (!pt1[i].equals(pt2[i])) {
if (!isNumber(pt1[i], pt2[i])) {
if (pt1[i].compareTo(pt2[i]) > 0)
return 1;
else
return -1;
} else {
int nu1 = Integer.parseInt(pt1[i]);
int nu2 = Integer.parseInt(pt2[i]);
if (nu1 > nu2)
return 1;
else
return -1;
}
}
}
if (pt1.length > i)
return 1;
else
return -1;
}
private static Boolean isNumber(String n1, String n2) {
// TODO Auto-generated method stub
try {
int nu1 = Integer.parseInt(n1);
int nu2 = Integer.parseInt(n2);
return true;
} catch (Exception x) {
return false;
}
}
}
Here is your given class:
private String studentName;
private String studentDOJ;
private String GlNumber; // alphanumeric
public Student(String studentName, String date, String glNumber) {
super();
this.studentName = studentName;
this.studentDOJ = date;
GlNumber = glNumber;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public String getStudentDOJ() {
return studentDOJ;
}
public void setStudentDOJ(String studentDOJ) {
this.studentDOJ = studentDOJ;
}
public String getGlNumber() {
return GlNumber;
}
public void setGlNumber(String glNumber) {
GlNumber = glNumber;
}
#Override
public String toString() {
return "Student [studentName=" + studentName + ", studentDOJ=" + studentDOJ + ", GlNumber="
+ GlNumber + "]";
}
#Override
public int compareTo(Student arg0) {
return 0;
}
}
And your the main method will be like:
public static void main(String args[]) throws ParseException {
ArrayList<Student> studentsList = new ArrayList<>();
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
Student std1 = new Student("Ram", "01-01-1981", "1203");
Student std2 = new Student("Raj", "01-01-1981", "1204");
Student std3 = new Student("Hanish", "01-01-1981", "403");
Student std4 = new Student("Hanish", "01-01-1981", "");
studentsList.add(std1);
studentsList.add(std2);
studentsList.add(std3);
studentsList.add(std4);
System.out.println(studentsList);
Collections.sort(studentsList, new studentDateComparator());
System.out.println(studentsList);
}
}
Use This to get your desired solution.
int extractInt(String s) {
String num = s.replaceAll("\\D", "");
// return 0 if no digits found
return num.isEmpty() ? 0 : Integer.parseInt(num);
}
#Override
public int compareTo(Student other) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
return Comparator.comparing((Student student) -> LocalDate.parse(student.getStudentDOJ(), formatter)).reversed()
.thenComparing(student -> extractInt(student.getGlNumber()))
.compare(this, other);
}
I have an ArrayList of objects, in every object I have a date and an hour that I have casted to int for the sorting.
I have already sorted the list of object by the date and now I want to sort the same array list by the hour keeping the sorting of the date.
A little example of the situation:
I have an event object with method
getDateEvent() and getHourEvent() that returns a value sortable of data and hour like YYYYMMDD and HHMM
And an arraylist of event already sorted by the date so i have to order the arraylist by the hour keeping the date sorted.
My code is actually this :
private ArrayList<Evento> SortingHour(ArrayList<Evento> SortingList){
int t=0;
int counter=0;
ArrayList<Evento> finale = new ArrayList<>();
ArrayList<Evento>[] Array = new ArrayList[SortingList.size()];
while(counter<SortingList.size()){
if( SortingList.get(counter).getDateEvent()).equals(SortingList.get(counter+1).getDateEvent()))) {
Array[t].add(SortingList.get(counter));
Array[t].add(SortingList.get(counter+1));
counter++;
}else{
t++;
Array[t].add(SortingList.get(counter));}
counter++;
}
for(int c=0;c<t;c++) {
for (int c1 = 0; c1 < Array[c].size(); c1++) {
for (int c2 = 0; c2 < Array[c].size(); c2++) {
if (Integer.parseInt(Array[c].get(c1).getHourEvent()) < Integer.parseInt(Array[c].get(c2).getHourEvent())) {
Collections.swap(Array[c], c1, c2);
}
}
}
}
for(int c=0; c<t;c++){
finale.addAll(Array[c]);
}
return finale;
}
Try something like this:
public ArrayList<Item> sort(List<Item> list) {
ArrayList<Item> dateSort= new ArrayList<>();
ArrayList<Item> result = new ArrayList<>();
if (list!= null && list.size() != 0) {
dateSort= new ArrayList<>(list);
Collections.sort(
dateSort, (o1, o2) -> Integer.compare(o1.getIntDate(), o2.getIntDate()));
int currentDate = dateSort.get(0).getIntDate();
ArrayList<Item> temp= new ArrayList<>();
for (int i = 1; i < dateSort.size(); i++) {
if (dateSort.get(i).getIntDate() > currentDate ) {
currentDate = dateSort.get(i).getIntDate();
result.addAll(timeSort(temp));
temp.clear();
temp.add(dateSort.get(i));
}
else{
temp.add(dateSort.get(i));
}
}
}
return result;
}
private ArrayList<Item> timeSort(List<Item> list) {
ArrayList<Item> timeSort= new ArrayList<>();
if (list!= null && list.size() != 0) {
timeSort= new ArrayList<>(list);
Collections.sort(
timeSort, (o1, o2) -> Integer.compare(o1.getIntTime(), o2.getIntTime()));
}
return timeSort;
}
I've created the below examples,
public class Timings {
private LocalDate date;
private int hour;
public Timings(LocalDate date, int hour) {
this.date = date;
this.hour = hour;
}
public LocalDate getDate() {
return date;
}
public int getHour() {
return hour;
}
#Override
public String toString() {
return "Timings{" +
"date=" + date +
", hour=" + hour +
'}';
}
}
public class Sorting {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2015, 02, 20);
LocalDate date1 = LocalDate.of(2018, 07, 12);
LocalDate date2 = LocalDate.of(2017, 05, 10);
Timings timings = new Timings(date, 10);
Timings timings1 = new Timings(date1, 8);
Timings timings2 = new Timings(date2, 12);
List<Timings> dateList = List.of(timings, timings1, timings2);
List<Timings> newList = dateList.stream()
.sorted( (a1, a2) -> a1.getDate().compareTo(a2.getDate()))
.sorted(Comparator.comparingInt(Timings::getHour))
.collect(Collectors.toList());
System.out.printf(newList);
}
}
in the above, the first sort method take care the sorting based on the date. The second take cares by the hour.
I got the below output
[Timings{date=2018-07-12, hour=8}, Timings{date=2015-02-20, hour=10}, Timings{date=2017-05-10, hour=12}]
Algorithm asked in one of the top company's interview, but I am not able to find a feasible solution. Need expert advice.
Suppose a student wants to attend maximum number of classes in a collage in a day (without any class overlap).
Input Format
The first line contains an integer n which gives the number of subjects offered on that day.
The next n lines follow containing the subject name (which is a string) followed by the start and end time for that subject in 24-hour format: hh:mm
For eg: Maths 10:00 11:00
Note: The timings are given in a 24-hour format and the subject names do not have spaces between them.
Output Format
The output should contain a number representing the maximum number of classes the student can choose.
Constraints
2 <= n <= 100
start time of a class < end time of class
Sample Input
4
Maths 16:00 18:00
ComputerScience 12:00 13:00
Physics 12:30 14:00
Chemistry 14:00 16:30
Sample Output
2
Explanation
ComputerScience starts the earliest and ends the earliest, so we take it first. After that, we cannot take Physics because it starts before ComputerScience is over. So we will take the next class, that is, Chemistry. But after Chemistry we cannot take Maths as Maths class starts before Chemistry class ends. So we can schedule a maximum of 2 classes for the day.
Below is my solution but I am not getting correct answer:
private void getMaxClass(String input) {
Map<String, Long> classTime = new LinkedHashMap<>();
Map<String, List<String>> timeMap = new LinkedHashMap<>();
String[] split = input.split(" ");
String subject = split[0];
String StartTime = split[1];
String endTime = split[2];
List<String> lvalue = new ArrayList<>();
lvalue.add(StartTime);
lvalue.add(endTime);
timeMap.put(subject, lvalue);
long difference = FineDifferenceInTime(StartTime, endTime);
classTime.put(subject, difference);
int count = 0;
Date date1 = null;
Date date2 = null;
Map<String, Long> sortedByValueDesc = classTime.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
for (Map.Entry<String, Long> entry : sortedByValueDesc.entrySet()) {
String sub = entry.getKey();
List<String> startEnd = timeMap.get(sub);
Date dateBefore = null;
Date dateAfter = null;
SimpleDateFormat format = new SimpleDateFormat("HH:mm");
try {
dateBefore = format.parse(startEnd.get(0));
dateAfter = format.parse(startEnd.get(1));
} catch (ParseException e) {
e.printStackTrace();
}
if (count == 0) {
count++;
try {
date1 = format.parse(startEnd.get(0));
date2 = format.parse(startEnd.get(1));
} catch (ParseException e) {
e.printStackTrace();
}
}
if (dateBefore.after(date1) && dateBefore.before(date2)) {
timeMap.remove(sub);
}
}
System.out.println(timeMap.size());
}
This is known in literature as the Interval Scheduling Problem. There are many ways to solve it, but since it is NP-complete (as there is a a polynomial reduction from VC) you'll necessarily need to explore all the combinations.
Greedy algorithms do exist (as is yours and the solution by #PriyankaDeshmukh), but they don't guarantee you the exact solution for all instances of the problem.
The solution below is a simple tree search: at each level we decide if we take a given course or not and move on to decide on the next course.
You could also implement a dynamic programming solution.
Here is a very good blog post covering solutions to the Interval Scheduling Problem.
I modelled a student class the following way:
class StudentClass {
public int _start;
public int _end;
public String _name;
public StudentClass(String name, int start, int end) {
_name = name;
_start = start;
_end = end;
}
public boolean overlapsWith(StudentClass other) {
return _start < other._end && _end > other._start;
}
public String toString() {
return "[" + _start + " - " + _end + "] " + _name;
}
}
There are classes to represent the time of the day, but their syntax/instantiation is a bit annoying/verbose -- feel free to improve this answer though! My Java is also very rusty, so feel free to correct me :-)
The Schedule class has a getMaxSchedule() which returns the solution to the problem -- what is the maximum number of classes a student can take, such that none of them overlap?
There are a few ways to optimize it, but I left it as-is as I believe it's easier to be understood.
public class Schedule {
List<StudentClass> _classes = new LinkedList<>();
public void addClass(String name, int startTime, int endTime) {
_classes.add(new StudentClass(name, startTime, endTime));
}
private int getMaxSchedule(int index, Collection<StudentClass> selected) {
// check if we reached the end of the array
if (index >= _classes.size()) {
return 0;
}
StudentClass current = _classes.get(index);
// check if taking this class doesn't conflict with the
// previously-selected set of classes
boolean canTakeThisClass = true;
for (StudentClass other : selected) {
if (current.overlapsWith(other)) {
canTakeThisClass = false;
break;
}
}
// check best schedule if we don't take this class
int best = getMaxSchedule(index + 1, selected);
// check best schedule if we take this class (if such is possible)
if (canTakeThisClass) {
selected.add(current);
best = Math.max(best, 1 + getMaxSchedule(index + 1, selected));
selected.remove(current);
}
return best;
}
public int getMaxSchedule() {
Collection<StudentClass> selected = new ArrayList<>();
return getMaxSchedule(0, selected);
}
}
You can see the result is 3 for your concrete problem through the following:
public static void main(String[] args) {
Schedule s = new Schedule();
s.addClass("Maths", 1600, 1800);
s.addClass("Computer Science", 1200, 1300);
s.addClass("Physics", 1230, 1400);
s.addClass("Chemistry", 1400, 1630);
System.out.println("maximum classes: " + s.getMaxSchedule());
}
I tried it with Python. It gives correct output.
I got it sorted by start time of class.
sorted_by_start = [{'sub': 'ComputerScience', 'start': '12:00', 'end': '13:00',
'duration': 60}, {'sub': 'Physics', 'start': '12:30', 'end': '14:00', 'duration':
90}, {'sub': 'Chemistry', 'start': '14:00', 'end': '16:30', 'duration': 150},
{'sub': 'Maths', 'start': '16:00', 'end': '18:00', 'duration': 120}]
possible_sub = set()
for a, b in itertools.combinations(sorted_by_start, 2):
strt_tme = datetime.datetime.strptime(a["end"], '%H:%M')
end_tme = datetime.datetime.strptime(b["start"], '%H:%M')
if(strt_tme <= end_tme) :
possible_sub.add((a["sub"],b["sub"]))
print("A student can attend these combinations of subject classes:",possible_sub)
print("Maximum classes student can attend in a day is: ",max(map(len,possible_sub)))
Here trick part is deciding how many combinations you can make. So, that you can do by adding additional for loop ranging from 2 to length of sorted_list and pass i to combinations(sorted_list, i) like this.
Ouput is :
A student can attend these combinations of subject classes: {('Physics', 'Maths'), ('Physics', 'Chemistry'), ('ComputerScience', 'Chemistry'), ('Compu
terScience', 'Maths')}
Maximum classes student can attend in a day is: 2
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
class InputSubject implements Comparable<InputSubject>{
String subject;
String startTime;
String endTime;
InputSubject(){
}
InputSubject(String subject, String startTime, String endTime){
this.subject = subject;
this.startTime = startTime;
this.endTime = endTime;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getStartTime() {
return startTime;
}
public void setStartTime(String startTime) {
this.startTime = startTime;
}
public String getEndTime() {
return endTime;
}
public void setEndTime(String endTime) {
this.endTime = endTime;
}
#Override
public int compareTo(InputSubject o) {
return this.endTime.compareTo(o.endTime);
}
}
public class SubjectSort {
static int getToatlSubject(List<InputSubject> list){
String sTime = null;
String eTime = null;
int count = 0;
int noOfSubject = 0;
for(InputSubject object : list){
if(count == 0){
count++;
eTime = object.getEndTime();
noOfSubject ++;
}
else {
if(object.getStartTime().compareTo(eTime) > 0){
eTime = object.getEndTime();
noOfSubject ++;
}
}
}
return noOfSubject;
}
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try {
int days = Integer.parseInt(reader.readLine());
for(int i = 0 ; i < days ;i++){
int sub = Integer.parseInt(reader.readLine());
List<InputSubject> list = new ArrayList<>();
for(int k = 0 ; k < sub ; k++){
InputSubject inputSubject = null;
String subDetails = reader.readLine();
String[] subAndTimes = subDetails.split(" ");
inputSubject = new InputSubject(subAndTimes[0],subAndTimes[1],subAndTimes[2]);
list.add(inputSubject);
}
Collections.sort(list);
System.out.println(getToatlSubject(list));
}
} catch (Exception e) {
}
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
class InputSubject implements Comparable<InputSubject>{
String subject;
String startTime;
String endTime;
InputSubject(){
}
InputSubject(String subject, String startTime, String endTime){
this.subject = subject;
this.startTime = startTime;
this.endTime = endTime;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getStartTime() {
return startTime;
}
public void setStartTime(String startTime) {
this.startTime = startTime;
}
public String getEndTime() {
return endTime;
}
public void setEndTime(String endTime) {
this.endTime = endTime;
}
#Override
public int compareTo(InputSubject o) {
return this.endTime.compareTo(o.endTime);
}
}
public class solution {
static int getToatlSubject(List<InputSubject> list){
String sTime = null;
String eTime = null;
int count = 0;
int noOfSubject = 0;
for(InputSubject object : list){
if(count == 0){
count++;
eTime = object.getEndTime();
noOfSubject ++;
}
else {
if(object.getStartTime().compareTo(eTime) >= 0){
eTime = object.getEndTime();
noOfSubject ++;
}
}
}
return noOfSubject;
}
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try {
int days = Integer.parseInt(reader.readLine());
for(int i = 0 ; i < days ;i++){
int sub = Integer.parseInt(reader.readLine());
List<InputSubject> list = new ArrayList<>();
for(int k = 0 ; k < sub ; k++){
InputSubject inputSubject = null;
String subDetails = reader.readLine();
String[] subAndTimes = subDetails.split(" ");
inputSubject = new InputSubject(subAndTimes[0],subAndTimes[1],subAndTimes[2]);
list.add(inputSubject);
}
Collections.sort(list);
System.out.println(getToatlSubject(list));
}
} catch (Exception e) {
}
}
}
i had same question in a coding round of a recruitment and I have solved it the following way and it gives correct answer. But unfortunately this code passed only 1 test case given in the challenge. I believe that the test cases were incorrect. Can anyone point out if I have missed something in code which might have led to this code failing other test cases?
import java.util.*;
import java.time.*;
import java.time.format.DateTimeFormatter;
import static java.time.temporal.ChronoUnit.*;
class solution {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
for (int i = 0; i < t; i++) {
int n=sc.nextInt();
String trash=sc.nextLine();
HashMap subjects=new HashMap<String,String>();
HashMap starttime=new HashMap<String,LocalTime>();
HashMap endtime=new HashMap<String,LocalTime>();
HashMap length=new HashMap<String,Long>();
for (int j = 0; j < n; j++){
String classes = sc.nextLine();
String[] classesArray=classes.split(" ");
String subject=classesArray[0];
if(classesArray[1].split(":")[0].length()==1){
classesArray[1]="0"+classesArray[1];
}
if(classesArray[2].split(":")[0].length()==1){
classesArray[2]="0"+classesArray[2];
}
LocalTime startTime=LocalTime.parse(classesArray[1]);
LocalTime endTime=LocalTime.parse(classesArray[2]);
DateTimeFormatter formatter = DateTimeFormatter.ISO_TIME;
Long lengthLecture=MINUTES.between(startTime, endTime);
subjects.put(subject,subject);
starttime.put(subject,startTime);
endtime.put(subject,endTime);
length.put(subject,lengthLecture);
String value = startTime.format(formatter);
String value1 = endTime.format(formatter);
// System.out.printf("Sub:%s st:%s et:%s length:%d\n",subject,value,value1,lengthLecture);
}
findMax(subjects,starttime,endtime,length);
//System.out.println(num);
}
}
public static void findMax(HashMap<String,String> subs,HashMap<String,LocalTime> strt,HashMap<String,LocalTime> endt,HashMap<String,Long> length){
int number=0;
List<Integer> list = new ArrayList<Integer>();
String curr,next1;
for (Map.Entry<String,String> entry : subs.entrySet()){
//System.out.println("Checkign for number: "+entry.getKey());
number=findnext(entry.getKey(),strt,endt);
// System.out.println("Number is: "+number);
list.add(number);
}
System.out.println(Collections.max(list));
}
public static int findnext(String subjt,HashMap<String,LocalTime> strt,HashMap<String,LocalTime> endt){
String sub=subjt;
int number=1;
LocalTime substtime=strt.get(subjt);
LocalTime subedtime=endt.get(subjt);
Long timetillstart=922337203L;
for (Map.Entry<String,LocalTime> entry : strt.entrySet()){
if((entry.getValue().compareTo(subedtime)>=0) && (MINUTES.between(subedtime, entry.getValue())<=timetillstart)){
sub=entry.getKey();
substtime=strt.get(entry.getKey());
timetillstart=MINUTES.between(subedtime, entry.getValue());
}
}
if(sub!=subjt){
number=number+findnext(sub,strt,endt);
}
return number;
}
}