I have to write a method with the stream api.In the method I should get the maximum of an integer value in an Object called "Winner", The Integer value I mean is the average speed value, I have to get the highest/fastest one.The Class looks like this
package U13_Lambdas_Streams.Streams;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
public class Winner {
private int year;
private String nationality;
private String name;
private String team;
private int lengthKm;
private Duration winningTime;
private int stageWins;
private int daysInYellow;
public static final List<Winner> tdfWinners = Arrays.asList(
new Winner(2006, "Spain", "Óscar Pereiro", "Caisse d'Epargne–
Illes Balears", 3657, Duration.parse("PT89H40M27S"), 8),
new Winner(2007, "Spain", "Alberto Contador", "Discovery
Channel", 3570, Duration.parse("PT91H00M26S"), 4),
new Winner(2008, "Spain", "Carlos Sastre", "Team CSC", 3559,
Duration.parse("PT87H52M52S"), 5),
new Winner(2009, "Spain", "Alberto Contador", "Astana", 3459,
Duration.parse("PT85H48M35S"), 7),
new Winner(2010, "Luxembourg", "Andy Schleck", "Team Saxo Bank",
3642, Duration.parse("PT91H59M27S"), 12),
new Winner(2011, "Australia", "Cadel Evans", "BMC Racing Team",
3430, Duration.parse("PT86H12M22S"), 2),
new Winner(2012, "Great Britain", "Bradley Wiggins", "Team Sky",
3496, Duration.parse("PT87H34M47S"), 14),
new Winner(2013, "Great Britain", "Chris Froome", "Team Sky",
3404, Duration.parse("PT83H56M20S"), 14),
new Winner(2014, "Italy", "Vincenzo Nibali", "Astana", 3661,
Duration.parse("PT89H59M06S"), 19),
new Winner(2015, "Great Britain", "Chris Froome", "Team Sky",
3360, Duration.parse("PT84H46M14S"), 16),
new Winner(2016, "Great Britain", "Chris Froome", "Team Sky",
3529, Duration.parse("PT89H04M48S"), 14)
);
public Winner(int year, String nationality, String name, String team, int
lengthKm, Duration winningTime, int daysInYellow) {
this.year = year;
this.nationality = nationality;
this.name = name;
this.team = team;
this.lengthKm = lengthKm;
this.winningTime = winningTime;
this.daysInYellow = daysInYellow;
}
public double getAveSpeed() {
return (getLengthKm() / (getWinningTime().getSeconds() / 3600));
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public String getNationality() {
return nationality;
}
public void setNationality(String nationality) {
this.nationality = nationality;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTeam() {
return team;
}
public void setTeam(String team) {
this.team = team;
}
public int getLengthKm() {
return lengthKm;
}
public void setLengthKm(int lengthKm) {
this.lengthKm = lengthKm;
}
public Duration getWinningTime() {
return winningTime;
}
public void setWinningTime(Duration winningTime) {
this.winningTime = winningTime;
}
public int getStageWins() {
return stageWins;
}
public void setStageWins(int stageWins) {
this.stageWins = stageWins;
}
public int getDaysInYellow() {
return daysInYellow;
}
public void setDaysInYellow(int daysInYellow) {
this.daysInYellow = daysInYellow;
}
#Override
public String toString() {
return name;
}
}
I tried It with this, but I still get 3 names and I dont know why
private static Double getMaxAVGSpeed() {
return Winner.tdfWinners
.stream()
.mapToDouble(Winner::getAveSpeed)
.max()
.orElse(Double.MAX_VALUE);
}
private static String winnerAVGSpeed() {
return Winner.tdfWinners
.stream()
.filter(winner -> winner.getAveSpeed() == getMaxAVGSpeed())
.map(Winner::getName)
.collect(Collectors.joining());
}
I hope you guys can help.
Regards, Lukas
EDIT: After reading Mark Keen's comment, it seems like the main fault is that the getAveSpeed() function does not cast the length to a double, so the result is rounded. I missed that when looking through the code. If the Winner class was provided as-is by the exercise, I would ask around to make sure that that is the intended behavior. However, the most likely case is that the methods of the class were written by OP, in which case casting the calculation would be a necessary change. Thanks, Mark.
I actually get 6 names when I run your code.
Your problem is that 6 Winners have the average speed of 40.0, which is the fastest/highest one of the set. So the result you're getting is correct. The main problem you have is figuring out the requirements of the exercise, to see if you have to print out just the maximum speed, the names of the Winners that have the maximum speed, or just one name that has the maximum speed.
One small caveat about your code, in the winnerAVGSpeed() function, you write
.filter(winner -> winner.getAveSpeed() == getMaxAVGSpeed())
on the stream you're manipulating. You're calling getMaxAVGSpeed() for every single element in the stream, which means that you're going through the stream and calculating the max speed once for every element of the list. The thing is, the max average speed will not change at any point, so you can calculate it once before you start manipulating the stream, store it in a variable, and then use the variable, to make your code more efficient.
If you only have to print out a single name that has the maximum velocity, you could also do this in a single stream operation, by using reduce, a stream function that allows you to compare and reduce a stream to a single element with a custom function. There's official documentation on this, but you can also find many different tutorials on how to use reduce on streams. It's not necessary though, your way seems more clear and useful to me.
Related
I have an application where a user provides me with the name of a field, e.g name or costInCents, and I have to sort by that field. I have ways of guaranteeing that the field name will be correct. This application causes the complication that I simply cannot make my class Comparable and implement a specific compareTo(), since with a custom implementation of compareTo() I need to know which fields / methods to use at implementation time.
So to achieve this goal, I am trying to use reflection in order to match the field to its accessor. Here's a MWE of what I want to do.
Class Product is a simple POJO class whose instances I want to pairwise compare:
public class Product
{
final String name;
final Integer quantity;
final Long costInCents;
public Product(final String name, final Integer quantity, final Long costInCents)
{
this.name = name;
this.quantity = quantity;
this.costInCents = costInCents;
}
public String getName()
{
return name;
}
public Integer getQuantity()
{
return quantity;
}
public Long getCostInCents()
{
return costInCents;
}
}
And my Main class, which is currently incomplete:
public class Main {
public static void main(String[] args) {
final Product[] productArray =
{
new Product("Clorox wipes", 50, 700L),
new Product("Desk chair", 10, 12000L),
new Product("TV", 5, 30000L),
new Product("Bookcase", 5, 12000L),
new Product("Water bottle", 20, 700L),
};
// The following void methods are supposed to sort in-place with something like Arrays.sort() or Collections.sort(),
// but I am also open to solutions involving stuff like Stream::sorted() or similar ones, which return a sorted array.
sortByField(productArray, "costInCents");
sortByField(productArray, "name");
}
private void sortByField(final Product[] productArray, final String sorterFieldName)
{
final Field sorterField = getSorterField(sorterFieldName, LiteProduct.class); // Gets the Field somehow
final Method sorterAccessor = getSorterAccessor(sorterField, LiteProduct.class); // Given the Field, this is easy
Arrays.sort((Product p1, Product p2)->((Comparable<?>)sorterAccessor.invoke(p1)).compareTo(sorterAccessor.invoke(p2)) > 0); // Capture of ? instead of Object
}
}
Unfortunately, the Arrays.sort() line results in a compile-time error with message Capture of ? instead of Object. I have tried casting the second argument to Comparable<?>, Comparable<? super sorterField.getType(), etc, with no luck. Ideas?
Possibly the best way - with sorting strategies. No need for reflection, compatible with more complex sorting logic:
Map<String, Comparator<Product>> sortingStrategies = new HashMap<>(){
{
put("costInCents", Comparator.comparingLong(p->p.costInCents));
put("quantity", Comparator.comparingLong(p->p.quantity));
put("name", Comparator.comparing(p->p.name));
}
};
private void sortByField(final Product[] productArray, final String sorterFieldName)
{
Arrays.sort(productArray, sortingStrategies.get(sorterFieldName));
}
You could write a Comparator for each field and use it by name via a Map:
public class Product
{
private final static Map<String,Comparator<Product>> COMPARATORS;
static {
COMPARATORS = new HashMap<>();
COMPARATORS.put("name", new NameComparator());
COMPARATORS.put("costInCents", new CostInCentsComparator());
}
final String name;
final Integer quantity;
final Long costInCents;
public Product(final String name, final Integer quantity, final Long costInCents)
{
this.name = name;
this.quantity = quantity;
this.costInCents = costInCents;
}
public String getName()
{
return name;
}
public Integer getQuantity()
{
return quantity;
}
public Long getCostInCents()
{
return costInCents;
}
static class NameComparator implements Comparator<Product> {
#Override
public int compare(Product o1, Product o2) {
return o1.getName().compareTo(o2.getName());
}
}
static class CostInCentsComparator implements Comparator<Product> {
#Override
public int compare(Product o1, Product o2) {
return o1.getCostInCents().compareTo(o2.getCostInCents());
}
}
static Comparator<Product> getComparator(String name) {
return COMPARATORS.get(name);
}
}
and use that in the main class
public class Main {
public static void main(String[] args) {
final Product[] productArray =
{
new Product("Clorox wipes", 50, 700L),
new Product("Desk chair", 10, 12000L),
new Product("TV", 5, 30000L),
new Product("Bookcase", 5, 12000L),
new Product("Water bottle", 20, 700L),
};
// The following void methods are supposed to sort in-place with something like Arrays.sort() or Collections.sort(),
// but I am also open to solutions involving stuff like Stream::sorted() or similar ones, which return a sorted array.
sortByField(productArray, "costInCents");
sortByField(productArray, "name");
}
private static void sortByField(final Product[] productArray, final String sorterFieldName)
{
Arrays.sort(productArray, Product.getComparator(sorterFieldName));
}
}
You may have to do minor changes like makeing it null safe or something
you can try this:
public class Test{
public static void main(String arg[]){
final Product[] productArray =
{
new Product("Clorox wipes", 50, 700L),
new Product("Desk chair", 10, 12000L),
new Product("TV", 5, 30000L),
new Product("Bookcase", 5, 12000L),
new Product("Water bottle", 20, 700L),
};
Arrays.sort(productArray,(p1, p2) -> p1.getName().compareTo(p2.getName()));
for(Product p: productArray){
System.out.println(p.getName());
}
}
}
in this case Comparator is a functional interface so I used lambad expression. but you can do this too
I would like to return the values of all the attributes from the BaseballPlayer class. The method that needs to do this must be the public string getBaseballPlayer(int i) method (because I need to reference this method inside getBaseballPlayers() to return all the values as an arraylist of strings) I'm having trouble doing this because all the attributes have different datatypes (int, String, Height).
I've tried doing this:
public String getBaseballPlayer(int i){
ArrayList <String> bArray = new ArrayList <String>();
bArray.add(getHometown());
bArray.add(getState());
bArray.add(getHighSchool());
bArray.add(getPosition());
However, it only works for the string methods, and doesn't necessarily return the actual values but rather the get methods for each string attribute.
public class BaseballPlayer extends Player implements Table {
private int num;
private String pos;
public BaseballPlayer( int a, String b, String c, int d,
String e, String f, String g, Height h){
super(a,ft,in,c,d,e,f,ht);
num = a;
pos = b;
}
public BaseballPlayer(){}
//Returns the value of a specific attribute. The input parameter start
with 0 for the first attribute, then 1 for the second attribute and so
on.
//you can use getBaseballPlayer(int i) in getBaseballPlayers( ) with a for
loop getting each getBaseballPlayer(int i).
public String getBaseballPlayer(int i){
ArrayList <String> bArray = new ArrayList <String>();
bArray.add(getHometown());
bArray.add(getState());
bArray.add(getHighSchool());
bArray.add(getPosition());
return (bArray);
}
//Returns the value of all attributes as an ArrayList of Strings.
public ArrayList <String> getBaseballPlayers(){
}
I'm just looking for the simplest way to return each attributes value, then using that method return each value as an arraylist of strings in another method.
It is not a good practice to return the whole object as one String. Unless and otherwise, you are forced to do this, do not try and do.
Well, if your requirement can't be changed, and if you want everything from the Baseball object to be in one string, you can concatenate all the parameters with a delimiter like ":".
Eg:
public String getBaseballPlayer(int i){
return getHometown() + ":" + getState() + ":" +getHighSchool() + ":" + getPosition();
}
On the invoking side, you can get the individual values from this String using "split()" method of String.
What you want to do, if you want to do it perfectly, is what Gson is for. It rides on top of simple JSON and can encode arbitrary classes, data structures, and other types into JSON such that you can reconstruct those objects easily from the JSON representation. It's easy to use considering how powerful what it does really is.
It's even easier to use regular JSON if you don't need to encode types that JSON won't handle by itself. In your case, it seems that this could be good enough. The great thing about JSON is that it's a standard. You don't have to choose an encoding scheme, and you already have libraries written in any language you can think of that can read your String'ified data.
Here's an example that roughly follows what your code is doing:
import org.codehaus.jackson.map.ObjectMapper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
public class BaseballPlayer {
private String name;
private String hometown;
private String state;
private int age;
private double height;
private String position;
static ObjectMapper mapper = new ObjectMapper();
public BaseballPlayer( String name, String hometown, String state, int age, double height, String position) {
this.name = name;
this.hometown = hometown;
this.state = state;
this.age = age;
this.height = height;
this.position = position;
}
public void setName(String name) {
this.name = name;
}
public void setHometown(String hometown) {
this.hometown = hometown;
}
public void setState(String state) {
this.state = state;
}
public void setAge(int age) {
this.age = age;
}
public void setHeight(float height) {
this.height = height;
}
public void setPosition(String position) {
this.position = position;
}
public String toString() {
return String.format("Name: %s from %s, %s (height: %.1f)", name, hometown, state, height);
}
public BaseballPlayer(){}
// Turn a BaseballPlayer object into a String
public String getAsJSON() {
Map<String, Object> info = new HashMap<>();
info.put("name", name);
info.put("hometown", hometown);
info.put("state", state);
info.put("age", age);
info.put("height", height);
info.put("position", position);
try {
return mapper.writeValueAsString(info);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
// Here's the method you ask for. I don't know what 'i' is supposed
// to do, since we're in the class for a single baseball player. You
// could create a class that contains a list of baseball players, but
// why not just use a List by itself, as I've done.
public String getBaseballPlayer(int i) {
return getAsJSON();
}
// Turn a list of BaseballPlayer objects into a list of Strings
public static List<String> playersToStrings(List<BaseballPlayer> players) {
List<String> r = new ArrayList<>();
for (BaseballPlayer player : players) {
r.add(player.getAsJSON());
}
return r;
}
// Turn a list of Strings into a list of BaseballPlayer objects
public static List<BaseballPlayer> stringsToPlayers(List<String> playerStrings) {
List<BaseballPlayer> r = new ArrayList<>();
for (String playerString : playerStrings) {
try {
BaseballPlayer player = mapper.readValue(playerString, BaseballPlayer.class);
r.add(player);
} catch (IOException e) {
e.printStackTrace();
}
}
return r;
}
public static void main(String... args) {
// Create a list of BaseballPlayer objects and print them
List<BaseballPlayer> players = new ArrayList<>();
players.add(new BaseballPlayer("Joe", "Boston", "MA", 25, 6.1, "First Base"));
players.add(new BaseballPlayer("Sam", "San Francisco", "CA", 28, 5.8, "Pitcher"));
players.add(new BaseballPlayer("Kelly", "Chicago", "IL", 32, 6.4, "Catcher"));
System.out.println(players);
// Convert the list to a list of Strings and print the list
List<String> playerStrings = playersToStrings(players);
System.out.println(playerStrings);
// Convert the Strings back into BaseballPlayer objects and print them
players = stringsToPlayers(playerStrings);
System.out.println(players);
}
}
and here's the resulting output:
[Name: Joe from Boston, MA (height: 6.1), Name: Sam from San Francisco, CA (height: 5.8), Name: Kelly from Chicago, IL (height: 6.4)]
[{"hometown":"Boston","name":"Joe","state":"MA","position":"First Base","age":25,"height":6.1}, {"hometown":"San Francisco","name":"Sam","state":"CA","position":"Pitcher","age":28,"height":5.8}, {"hometown":"Chicago","name":"Kelly","state":"IL","position":"Catcher","age":32,"height":6.4}]
[Name: Joe from Boston, MA (height: 6.1), Name: Sam from San Francisco, CA (height: 5.8), Name: Kelly from Chicago, IL (height: 6.4)]
Here, each player is turned into JSON individually. A few more lines of code, and you could turn an array of Baseball Player objects into a single String.
If this JSON-only solution isn't good enough for you, check out Gson. It can preserve all Java types. It just takes a bit more setup to describe how each of your objects should be turned into JSON and back.
I have simple class
public class ActiveAlarm {
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
}
and List<ActiveAlarm> con. How to sort in ascending order by timeStarted, then by timeEnded? Can anybody help? I know in C++ with generic algorithm and overload operator <, but I am new to Java.
Using Comparator
For Example:
class Score {
private String name;
private List<Integer> scores;
// +accessor methods
}
Collections.sort(scores, new Comparator<Score>() {
public int compare(Score o1, Score o2) {
// compare two instance of `Score` and return `int` as result.
return o2.getScores().get(0).compareTo(o1.getScores().get(0));
}
});
With Java 8 onwards, you can simply use lambda expression to represent Comparator instance.
Collections.sort(scores, (s1, s2) -> { /* compute and return int */ });
Either make ActiveAlarm implement Comparable<ActiveAlarm> or implement Comparator<ActiveAlarm> in a separate class. Then call:
Collections.sort(list);
or
Collections.sort(list, comparator);
In general, it's a good idea to implement Comparable<T> if there's a single "natural" sort order... otherwise (if you happen to want to sort in a particular order, but might equally easily want a different one) it's better to implement Comparator<T>. This particular situation could go either way, to be honest... but I'd probably stick with the more flexible Comparator<T> option.
EDIT: Sample implementation:
public class AlarmByTimesComparer implements Comparator<ActiveAlarm> {
#Override
public int compare(ActiveAlarm x, ActiveAlarm y) {
// TODO: Handle null x or y values
int startComparison = compare(x.timeStarted, y.timeStarted);
return startComparison != 0 ? startComparison
: compare(x.timeEnded, y.timeEnded);
}
// I don't know why this isn't in Long...
private static int compare(long a, long b) {
return a < b ? -1
: a > b ? 1
: 0;
}
}
JAVA 8 and Above Answer (Using Lambda Expressions)
In Java 8, Lambda expressions were introduced to make this even easier! Instead of creating a Comparator() object with all of it's scaffolding, you can simplify it as follows: (Using your object as an example)
Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.timeStarted-a2.timeStarted);
or even shorter:
Collections.sort(list, Comparator.comparingInt(ActiveAlarm ::getterMethod));
That one statement is equivalent to the following:
Collections.sort(list, new Comparator<ActiveAlarm>() {
#Override
public int compare(ActiveAlarm a1, ActiveAlarm a2) {
return a1.timeStarted - a2.timeStarted;
}
});
Think of Lambda expressions as only requiring you to put in the relevant parts of the code: the method signature and what gets returned.
Another part of your question was how to compare against multiple fields. To do that with Lambda expressions, you can use the .thenComparing() function to effectively combine two comparisons into one:
Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.timeStarted-a2.timeStarted
.thenComparing ((ActiveAlarm a1, ActiveAlarm a2) -> a1.timeEnded-a2.timeEnded)
);
The above code will sort the list first by timeStarted, and then by timeEnded (for those records that have the same timeStarted).
One last note: It is easy to compare 'long' or 'int' primitives, you can just subtract one from the other. If you are comparing objects ('Long' or 'String'), I suggest you use their built-in comparison. Example:
Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.name.compareTo(a2.name) );
EDIT: Thanks to Lukas Eder for pointing me to .thenComparing() function.
We can sort the list in one of two ways:
1. Using Comparator : When required to use the sort logic in multiple places
If you want to use the sorting logic in a single place, then you can write an anonymous inner class as follows, or else extract the comparator and use it in multiple places
Collections.sort(arrayList, new Comparator<ActiveAlarm>() {
public int compare(ActiveAlarm o1, ActiveAlarm o2) {
//Sorts by 'TimeStarted' property
return o1.getTimeStarted()<o2.getTimeStarted()?-1:o1.getTimeStarted()>o2.getTimeStarted()?1:doSecodaryOrderSort(o1,o2);
}
//If 'TimeStarted' property is equal sorts by 'TimeEnded' property
public int doSecodaryOrderSort(ActiveAlarm o1,ActiveAlarm o2) {
return o1.getTimeEnded()<o2.getTimeEnded()?-1:o1.getTimeEnded()>o2.getTimeEnded()?1:0;
}
});
We can have null check for the properties, if we could have used 'Long' instead of 'long'.
2. Using Comparable(natural ordering): If sort algorithm always stick to one property:
write a class that implements 'Comparable' and override 'compareTo' method as defined below
class ActiveAlarm implements Comparable<ActiveAlarm>{
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
public ActiveAlarm(long timeStarted,long timeEnded) {
this.timeStarted=timeStarted;
this.timeEnded=timeEnded;
}
public long getTimeStarted() {
return timeStarted;
}
public long getTimeEnded() {
return timeEnded;
}
public int compareTo(ActiveAlarm o) {
return timeStarted<o.getTimeStarted()?-1:timeStarted>o.getTimeStarted()?1:doSecodaryOrderSort(o);
}
public int doSecodaryOrderSort(ActiveAlarm o) {
return timeEnded<o.getTimeEnded()?-1:timeEnded>o.getTimeEnded()?1:0;
}
}
call sort method to sort based on natural ordering
Collections.sort(list);
In java8+ this can be written in single line as follows:
collectionObjec.sort(comparator_lamda) or comparator.comparing(CollectionType::getterOfProperty)
code:
ListOfActiveAlarmObj.sort((a,b->a.getTimeStarted().compareTo(b.getTimeStarted())))
or
ListOfActiveAlarmObj.sort(Comparator.comparing(ActiveAlarm::getTimeStarted))
public class ActiveAlarm implements Comparable<ActiveAlarm> {
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
public int compareTo(ActiveAlarm a) {
if ( this.timeStarted > a.timeStarted )
return 1;
else if ( this.timeStarted < a.timeStarted )
return -1;
else {
if ( this.timeEnded > a.timeEnded )
return 1;
else
return -1;
}
}
That should give you a rough idea. Once that's done, you can call Collections.sort() on the list.
Since Java8 this can be done even cleaner using a combination of Comparator and Lambda expressions
For Example:
class Student{
private String name;
private List<Score> scores;
// +accessor methods
}
class Score {
private int grade;
// +accessor methods
}
Collections.sort(student.getScores(), Comparator.comparing(Score::getGrade);
Java-8 solution using Stream API:
A. When timeStarted and timeEnded are public (as mentioned in the requirement) and therefore do not (need to) have public getter methods:
List<ActiveAlarm> sorted =
list.stream()
.sorted(Comparator.comparingLong((ActiveAlarm alarm) -> alarm.timeStarted)
.thenComparingLong((ActiveAlarm alarm) -> alarm.timeEnded))
.collect(Collectors.toList());
B. When timeStarted and timeEnded have public getter methods:
List<ActiveAlarm> sorted =
list.stream()
.sorted(Comparator.comparingLong(ActiveAlarm::getTimeStarted)
.thenComparingLong(ActiveAlarm::getTimeEnded))
.collect(Collectors.toList());
If you want to sort the original list itself:
A. When timeStarted and timeEnded are public (as mentioned in the requirement) and therefore do not (need to) have public getter methods:
list.sort(Comparator.comparingLong((ActiveAlarm alarm) -> alarm.timeStarted)
.thenComparingLong((ActiveAlarm alarm) -> alarm.timeEnded));
B. When timeStarted and timeEnded have public getter methods:
list.sort(Comparator.comparingLong(ActiveAlarm::getTimeStarted)
.thenComparingLong(ActiveAlarm::getTimeEnded));
Guava's ComparisonChain:
Collections.sort(list, new Comparator<ActiveAlarm>(){
#Override
public int compare(ActiveAlarm a1, ActiveAlarm a2) {
return ComparisonChain.start()
.compare(a1.timestarted, a2.timestarted)
//...
.compare(a1.timeEnded, a1.timeEnded).result();
}});
We can use the Comparator.comparing() method to sort a list based on an object's property.
class SortTest{
public static void main(String[] args) {
ArrayList<ActiveAlarm> activeAlarms = new ArrayList<>(){{
add(new ActiveAlarm("Alarm 1", 5, 10));
add(new ActiveAlarm("Alarm 2", 2, 12));
add(new ActiveAlarm("Alarm 3", 0, 8));
}};
/* I sort the arraylist here using the getter methods */
activeAlarms.sort(Comparator.comparing(ActiveAlarm::getTimeStarted)
.thenComparing(ActiveAlarm::getTimeEnded));
System.out.println(activeAlarms);
}
}
Note that before doing it, you'll have to define at least the getter methods of the properties you want to base your sort on.
public class ActiveAlarm {
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
public ActiveAlarm(String name, long timeStarted, long timeEnded) {
this.name = name;
this.timeStarted = timeStarted;
this.timeEnded = timeEnded;
}
public long getTimeStarted() {
return timeStarted;
}
public long getTimeEnded() {
return timeEnded;
}
#Override
public String toString() {
return name;
}
}
Output:
[Alarm 3, Alarm 2, Alarm 1]
Employee POJO Class
package in.ac.adit.oop.sort;
public class Employee {
private int id;
private String name;
private String department;
public int getId() {
return id;
}
public Employee() {
super();
}
public Employee(int id, String name, String department) {
super();
this.id = id;
this.name = name;
this.department = department;
}
#Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", department=" + department + "]";
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
}
Employee Class To Manage Employee
package in.ac.adit.oop.sort;
import java.util.ArrayList;
import java.util.List;
public class Example {
public static void main(String[] args) {
/*
* Create 10 Employee Object
*/
Employee emp1 = new Employee(1, "Nayan", "IT");
Employee emp2 = new Employee(2, "Siddarth", "CP");
Employee emp3 = new Employee(3, "Samarth", "AE");
Employee emp4 = new Employee(4, "Bhavesh", "CV");
Employee emp5 = new Employee(5, "Sam", "FT");
Employee emp6 = new Employee(6, "Keyur", "IT");
Employee emp7 = new Employee(7, "Bala", "ME");
Employee emp8 = new Employee(8, "Mitul", "ME");
Employee emp9 = new Employee(9, "Kamlesh", "EE");
Employee emp10 = new Employee(10, "Piyush", "EE");
/*
* List of Employee Object
*/
List<Employee> employeeList = new ArrayList<Employee>();
employeeList.add(emp1);
employeeList.add(emp2);
employeeList.add(emp3);
employeeList.add(emp4);
employeeList.add(emp5);
employeeList.add(emp6);
employeeList.add(emp7);
employeeList.add(emp8);
employeeList.add(emp9);
employeeList.add(emp10);
CustomObjectSort customObjectSort = new CustomObjectSort();
List<Employee> sortByDepartment = customObjectSort.sortByDepartment(employeeList);
/*
* Sorted By Department
*/
for (Employee employee : sortByDepartment) {
System.out.println(employee);
}
/*
* Sorted By Name
*/
List<Employee> sortByName = customObjectSort.sortByName(employeeList);
for (Employee employee : sortByName) {
System.out.println(employee);
}
/*
* Sorted By Id
*/
List<Employee> sortById = customObjectSort.sortById(employeeList);
for (Employee employee : sortById) {
System.out.println(employee);
}
}
}
Custom Sorting
package in.ac.adit.oop.sort;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class CustomObjectSort {
public List<Employee> sortByName(List<Employee> employeeList) {
Collections.sort(employeeList, new Comparator<Employee>() {
#Override
public int compare(Employee employee1, Employee employee2) {
return employee1.getName().compareTo(employee2.getName());
}
});
return employeeList;
}
public List<Employee> sortByDepartment(List<Employee> employeeList) {
Collections.sort(employeeList, new Comparator<Employee>() {
#Override
public int compare(Employee employee1, Employee employee2) {
return employee1.getDepartment().compareTo(employee2.getDepartment());
}
});
return employeeList;
}
public List<Employee> sortById(List<Employee> employeeList) {
Collections.sort(employeeList, new Comparator<Employee>() {
#Override
public int compare(Employee employee1, Employee employee2) {
return employee1.getId() - employee2.getId();
}
});
return employeeList;
}
}
You can use Collections.sort and pass your own Comparator<ActiveAlarm>
In java you need to use the static Collections.sort method. Here is an example for a list of CompanyRole objects, sorted first by begin and then by end. You can easily adapt for your own object.
private static void order(List<TextComponent> roles) {
Collections.sort(roles, new Comparator() {
#Override
public int compare(Object o1, Object o2) {
int x1 = ((CompanyRole) o1).getBegin();
int x2 = ((CompanyRole) o2).getBegin();
if (x1 != x2) {
return x1 - x2;
} else {
int y1 = ((CompanyRole) o1).getEnd();
int y2 = ((CompanyRole) o2).getEnd();
return y2 - y1;
}
}
});
}
You can call Collections.sort() and pass in a Comparator which you need to write to compare different properties of the object.
As mentioned you can sort by:
Making your object implement Comparable
Or pass a Comparator to Collections.sort
If you do both, the Comparable will be ignored and Comparator will be used. This helps that the value objects has their own logical Comparable which is most reasonable sort for your value object, while each individual use case has its own implementation.
public class ActiveAlarm {
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
}
List<ActiveAlarm> con = new ArrayList<ActiveAlarm>();
Collections.sort(con , (a1, a2) -> a1.timeStarted.compareTo(a2.timeStarted));
Collections.sort(con , (a1, a2) -> a1.timeEnded.compareTo(a2.timeEnded));
Here's what did the trick for me.
Was much shorter and easier than everything else I found:
Collections.sort(listName, Comparator.comparing(Object::getProperty).reversed());
The ".reversed()" part at the end was a requirement for my specific project but I'm sharing it too, as it took a while to find it
The best and the easiest way to sort any list of objects in Java (Java 8 and above).
Lets sort a basket of fruits based on the property "fruitName"
Fruit POJO:
class Fruit
{
int price;
String fruitName;
public Fruit(int price, String fruitName) {
super();
this.price = price;
this.fruitName = fruitName;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getFruitName() {
return fruitName;
}
public void setFruitName(String fruitName) {
this.fruitName = fruitName;
}
#Override
public String toString() {
return "Fruits [price=" + price + ", fruitName=" + fruitName + "]";
}
}
Now lets add fruits into a list and then sort it
List<Fruit> basketOfFruits = new ArrayList<>();
basketOfFruits.add(new Fruit(123, "oranges"));
basketOfFruits.add(new Fruit(45, "nectarine"));
basketOfFruits.add(new Fruit(369, "blueberries"));
basketOfFruits.add(new Fruit(248, "apple"));
basketOfFruits.add(new Fruit(968, "peaches"));
basketOfFruits.add(new Fruit(436, "grapes"));
basketOfFruits.add(new Fruit(596, "figs"));
//sorting by the property fruitName
Collections.sort(basketOfFruits, (f1, f2)->{return f1.getFruitName().compareTo(f2.getFruitName());});
You can now print the list (i.e basketOfFruits) and the fruits in the list would be sorted in ASCENDING order (lexicographically).
The output would look like this:
[Fruits [price=248, fruitName=apple], Fruits [price=369, fruitName=blueberries], Fruits [price=596, fruitName=figs], Fruits [price=436, fruitName=grapes], Fruits [price=45, fruitName=nectarine], Fruits [price=123, fruitName=oranges], Fruits [price=968, fruitName=peaches]]
Instead of Collections.sort(), Java streams can also be used (Java 8 and above). The following is the code using Java streams
List<Fruit> sortedFruits = basketOfFruits.stream().sorted( (f1, f2)->{return f1.getFruitName().compareTo(f2.getFruitName());}).collect(Collectors.toList());
here the list is sorted in the same manner as Collections.sort(), but the sorted items would be stored/collected in another list "sortedFruits". So, if we want to print the sorted items of the list, we need to print "sortedFruits" instead of "basketOfFruits" in this case
I've been asked to program a small online sales aplication.
It sounds very simple in theory (but it's been a hell for me). I'm just supposed to have an arrayList with about 5 products and then have a client buy 1 to 5 products and print the sales total.
public class Product {
private String name;
private double price;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
public String printInfo() {
return "Product: " + name + " Cost: " + price;
}
}
Then I have a client class:
public class Cliente {
private String name;
private int numPedido;
ArrayList<Producto> products = new ArrayList<Producto>();
public void listBuilder() {
Producto shirt = new Producto("Shirt", 30);
Producto tshirt = new Producto("T-Shirt", 40);
Producto sweater = new Producto("Sweater", 50);
}
public Cliente(String name, int numPedido) {
this.name = name;
this.numPedido = numPedido;
}
public Cliente() {
}
public String getName() {
return name;
}
public int getNumPedido() {
return (int) (Math.random() * 100);
}
public void addNewClient() {
name = JOptionPane.showInputDialog("Nombre: ");
}
public String printInfo() {
return "Nombre: " + name;
}
}
Right now I'm stuck thinking on how to make a client select a product and get that attached to him. I was thinking on making an arrayList of an arrayList but I'm sure that would complicate things. I know there is probably an easier way to connect them but I can't think of any. The option I have in mind is a method which shows numbers from 1 to 3(corresponding to each product) and when the user picks one it should return the price of the item.
Still not sure how to implement it in a way that the user can pick multiple products.
EDIT:
I also have an admin class that goes like this:
public class Admin {
private Client[] clientList;
public AdminPedidos() {
clientList = new Client[2];
}
public void AddContact() {
clienteList[0] = addProduct();
clienteList[1] = addProduct();
fillList();
}
public Cliente addProduct() {
String contactoString = JOptionPane.showInputDialog("Are you a new client? Press 1 if yes.");
if (contactoString.equals("1")) {
return new Cliente();
} else {
return new Cliente(); //just for testing
}
}
private void fillList() {
for (Client i : clientList) {
i.addNewClient();
}
}
public void printContact() {
for (Client i : clientList) {
System.out.println(i.printInfo());
}
}
}
You can have some purchaseProduct method attached to each Client.
public void purchaseProduct(Product product) { this.products.add(product); }
Then each Client you instantiate (Client client = new Client(name, id);) can add Products to his/her cart with the purchaseProduct method.
I'm assuming you are using some kind of user input method (Scanner). With that you can read the user's input of which Product they want and accordingly call the function with the right Product.
The listBuilder function doesn't quite make sense to me btw (and after your edit, it's really hard to make sense of what the Admin class should be/represent).
Edit: You would probably want to create an ArrayList<Product> which will be attached to each client, which you already have. I sense that you have a difficulty deciding where to put your actual Products. You should not put them inside your Client class for sure.
You should think about who/where they are going to be used. Probably in main right? So just instantiate them there first and then the Client could choose which one to purchase (via the method I introduced before):
client.purchaseProduct(product);
I have situation. I have to create a Sports Club system in JAVA. There should be a class your for keeping track of club name, president name and braches the club has. For each sports branch also there should be a class for keeping track of a list of players. Also each player should have a name, number, position and salary.
So, I come up with this. Three seperate classes:
public class Team
{
String clubName;
String preName;
Branch []branches;
}
public class Branch
{
Player[] players;
}
public class Player
{
String name;
String pos;
int salary;
int number;
}
The problems are creating Branch[] in another class and same for the Player[]. Is there any simplier thing to do this? For example, I want to add info for only the club name, president name and branches of the club, in this situation, won't i have to enter players,names,salaries etc. since they are nested in each other. I hope i could be clear. For further questions you can ask.
Here's a more complete, formal example of your scenario using conventional Accessors/Mutators (getters/setters), constructors, and Lists. The main() method below illustrates how to use your classes.
public class SportsClub
{
public static void main(String[] args)
{
//Create a team without any branches
Team myTeam = new Team("Southpaws", "South");
//Create a new Branch without any players
Branch myBranch = new Branch();
//Add myBranch to myTeam
myTeam.getBranches().add(myBranch);
//Create a new player
Player myPlayer = new Player("Bob", "Center", 120, 3);
//Add myPlayer to myBranch (and therefore myTeam)
myBranch.getPlayers().add(player);
}
}
public class Team
{
private String clubName;
private String preName;
private List<Branch> branches;
public Team(String clubName, String preName)
{
this.clubName = clubName;
this.preName = preName;
branches = new ArrayList<Branch>();
}
public String getClubName() { return clubName; }
public String getPreName() { return preName; }
public List<Branch> getBranches() { return branches; }
public void setClubName(String clubName) { this.clubName = clubName; }
public void setPreName(String preName) { this.preName = preName; }
public void setBranches(List<Branch> branches) { this.branches = branches; }
}
public class Branch
{
private List<Player> players = new ArrayList<Player>();
public Branch() {}
public List<Player> getPlayers() { return players; }
public void setPlayers(List<Player> players) { this.players = players; }
}
public class Player
{
private String name;
private String pos;
private Integer salary;
private Integer number;
public Player(String name, String pos, Integer salary, Integer number)
{
this.name = name;
this.pos = pos;
this.salary = salary;
this.number = number;
}
public String getName() { return name; }
public String getPos() { return pos; }
public Integer getSalary() { return salary; }
public Integer getNumber() { return number; }
public void setName(String name) { this.name = name; }
public void setPos(String pos) { this.pos = pos; }
public void setSalary(Integer salary) { this.salary = salary; }
public void setNumber(Integer number) { this.number = number; }
}
To answer your question, yes, you can create these objects without populating the Lists with players. The SportsClub.main() above illustrates that.
I would use a List rather than an array since they're (easily) dynamically resizable, but otherwise, you're on the right track.
Think about encapsulation and visibility too. Make all those fields private and provide accessors.
You could create an empty Branch[] array (or better yet - a list) at initialization and add to it later, that way you don't have to enter all the information upon creation - same goes for Player[].
Something like:
public class Team
{
String clubName;
String preName;
private List<Branch> branches;
public Team (String club, String pre) {
clubName = club;
preName = pre;
branches = new LinkedList<Branch>();
}
public void addBranch (Branch branch) {..}
}
public class Branch
{
private List<Player> players;
public Branch () {
players = new LinkedList<Player>();
}
public void addPlayer (Player player) {..}
}
public class Player
{
String name;
String pos;
int salary;
int number;
}
I think that's good. You should probably have methods in the classes to manage your information though--don't try to do anything serious from "Outside" these classes.
to be more specific: All your members should be private and only used/accessed from within the classes--also in general avoid setters and getters, instead ask the class to do things for you.
For example, if you wanted to know how many players were in a branch, you would call branch.countPlayers, not access the Player array to count the players from outside.
If you wanted to know how many players were in a team, you would call team.countPlayers which would call branch.countPlayers for each Branch, sum them up and return the value.
If you wanted to see which branch a player was in, you would call Team.findPlayer(playerName). Team would call branch.hasPlayer(playerName) on each branch until it returned a true, then Team would return the Branch object that returned true.
etc.
Note that this resolves your "Populated or not" issue. If you simply have methods like "hasBranch()", "addBranch()", "removeBranch()" then it doesn't matter how or when you populate the branches array since you control it all within the Team class you can change it's implementation at any time and not change a single line outside that class.
You won't have to enter anything into the players array, nor the branch[]. Provided you make the fields accessible, of have properties, you will be able to put them in however you like.
The class structure looks good to me, but a List would be better so that you don't have to worry about resizing arrays down the road.
Nothing wrong with your classes. I personally would use a strongly-typed List to store the branches and players:
public class Team
{
String clubName;
String preName;
List<Branch> branches;
}
public class Branch
{
List<Player> players;
}
Not sure of the requirement, but you'd probably want to have some kind of identifier or name for each Branch, right?
There's nothing in these classes that forces you to create new players just to instantiate a Branch. The list of Players can remain null or empty until you need them.