So, I have been playing around with java streams a bit, and found something very frustrating.
I want to make a list of this type of object (Customer), and after that use a stream to filter out all those objects where glad == false.
package com.company;
public class Customer {
public String name;
public int points;
public boolean glad;
public Customer(String name, int points, boolean glad) {
this.name = name;
this.points = points;
this.glad = glad;
}
public boolean isGlad() {
return this.glad;
}
}
Whenever I try doing it with a regular array, everything seems to work just fine:
Customer kunde1 = new Customer("jens", 20, true);
Customer kunde2 = new Customer("marie", 20, false);
Customer kunde3 = new Customer("niels", 20, false);
Customer kunde4 = new Customer("jens", 20, true);
Customer kunde5 = new Customer("jens", 20, true);
Customer[] kunderne = {kunde1,kunde2,kunde3,kunde4,kunde5};
Customer[] filtered = Stream.of(kunderne)
.filter(Customer::isGlad)
.toArray(Customer[]::new);
But whenever I try to create the stream from something other than an array, like an ArrayList, I am not able to access the object attributes within my lambda statement
ArrayList<Customer> customers = new ArrayList<>();
Customer kunde1 = new Customer("jens", 20, true);
Customer kunde2 = new Customer("marie", 20, false);
Customer kunde3 = new Customer("niels", 20, false);
Customer kunde4 = new Customer("jens", 20, true);
Customer kunde5 = new Customer("jens", 20, true);
customers.add(kunde1);
customers.add(kunde2);
customers.add(kunde3);
customers.add(kunde4);
customers.add(kunde5);
Customer[] filtered = Stream.of(kunderne)
.filter(Customer::isGlad)
.toArray(Customer[]::new);
But this code won't even run. Why does this happen, and why does it only seem to work with arrays?
There is no such a method as Stream.of(List<T>).
You should use cusomters.stream() which will convert your list into the stream.
That's happening because Stream.of(cusomters) is creating the one element Stream with the ArrayList object inside - obviously there is not method
public static boolean isGlad(ArrayList<Customer> customers) {
return false;
}
and this is why the code is not running
When you are passing Customer[] object to the Stream.of instead of of method version
public static<T> Stream<T> of(T t)
overloaded
public static<T> Stream<T> of(T... values)
is being used and everything is fine
Here is what you wanted to do.
Customer[] filtered = Stream.of(kunderne).filter(Customer::isGlad).map(
cust -> new Customer(cust.name, cust.points, cust.glad)).toArray(
Customer[]::new);
for (Customer c : filtered) {
System.out.println(c.name + " " + c.points + " " + c.glad);
}
You needed to map the filtered customer to a new customer and then put those in an array. Another option would be to add a constructor that takes an existing customer and uses that as input. Here is how that would work.
Customer[] filtered = Stream.of(kunderne).filter(Customer::isGlad).map(
Customer::new).toArray(Customer[]::new);
for (Customer c : filtered) {
System.out.println(c.name + " " + c.points + " " + c.glad);
}
// modified customer class with additional constructor
class Customer {
public String name;
public int points;
public boolean glad;
public Customer(String name, int points, boolean glad) {
this.name = name;
this.points = points;
this.glad = glad;
}
public Customer(Customer cust) {
this(cust.name, cust.points, cust.glad);
}
public boolean isGlad() {
return this.glad;
}
}
Related
So I have this class which reads from 2 files and fills 2 Arraylists
with Contact Objects. Now I want to Merge these Arraylists to a new
Arraylist which then I want to Sort and eliminate duplicates. My
problem is: How do I get the filled Arraylists to another method so I
can do the sorting?
Here is my Code:
import java.util.List;
import java.util.Scanner;
final class Addressbook{
public List<Contact> contacts1 = new ArrayList<Contact>();
public List<Contact> contacts2= new ArrayList<Contact>();
public List<Contact> allcontacts = new ArrayList<Contact>();
public void readContacts1(Scanner scanner1) {
scanner1.useDelimiter(";");
while (scanner1.hasNext()) {
final Contact contact= readContacts1(scanner1);
contacts1.add(Contact);
}
}
public void readContacts2(Scanner scanner2) {
while (scanner2.hasNext()) {
final Contact contact = readContacts2(scanner2);
contacts.add(contact);
}
}
public int ContactSearch1(Contact c) {
for (int i = 0; i < contacts1.size(); i++)
if (contacts1.get(i).equals(c))
return i;
return -1;
}
public int ContactSearch2(Contact c) {
for (int i = 0; i < contacts2.size(); i++)
if (contacts2.get(i).equals(c))
return i;
return -1;
}
private static Contact readContact1(Scanner scanner1) {
scanner1.useDelimiter(";");
final String name= scanner1.next();
final String lastname = scanner1.next();
final String address = scanner1.next();
final String number = scanner1.next();
final Contact contact= new Contact(name, lastname, address, number);
return contact;
}
private static Contact ReadContact2(Scanner scanner2) {
scanner2.useDelimiter(";");
final String name= scanner2.next();
final String lastname = scanner2.next();
final String address = scanner2.next();
final String number = scanner2.next();
final Contact contact= new Contact(name, lastname, address, number);
return contact;
}
}
First, the provided code contains a lot of duplicated parts which may easily be encapsulated in a separate helper class which takes care of reading and searching the lists.
final class Addressbook{
private List<Contact> contacts1;
private List<Contact> contacts2;
private List<Contact> allContacts;
private static class ContactHelper {
public static List<Contact> readContacts(Scanner scanner) {
// scanner.setDelimiter(";"); // it's better to set this parameter in the call
List<Contact> result = new ArrayList<>();
boolean hasData = scanner.hasNext();
while (hasData) {
final String name= scanner.next();
final String lastname = (hasData &= scanner.hasNext()) ? scanner.next() : "NO_LAST_NAME";
final String address = (hasData &= scanner.hasNext()) ? scanner.next() : "NO_ADDRESS";
final String number = (hasData &= scanner.hasNext()) ? scanner.next() : "NO_NUMBER";
result.add(new Contact(name, lastname, address, number));
hasData = scanner.hasNext();
}
return result;
}
public static int indexOfContact(Contact contact, List<Contact> list) {
Objects.requireNonNull(contact);
Objects.requireNonNull(list);
for (int i = 0, n = list.size(); i < n; i++) {
if (contact.equals(list.get(i))) {
return i;
}
}
return -1;
}
}
}
Then appropriate methods to set fields contacts1, contacts2 should use the helper's methods:
// class AddressBook
public void readContacts1(Scanner scanner) {
contacts1 = ContactHelper.readContacts(scanner);
}
public void readContacts2(Scanner scanner) {
contacts2 = ContactHelper.readContacts(scanner);
}
A method to join the lists, sort them, and remove the duplicates can be implemented using TreeSet if class Contact implements interface Comparable required for sorting the contacts in their natural order, otherwise custom comparator must be provided.
// another helper method
public static List<Contact> joinContacts(List<Contact> ... contactLists) {
Set<Contact> sortedWithoutDups = new TreeSet<>();
for (List<Contact> list : contactLists) {
if (null != list) {
sortedWithoutDups.addAll(list);
}
}
return new ArrayList<>(sortedWithoutDups);
}
// setting allContacts
public void joinContacts() {
allContacts = AddressBook.joinContacts(contacts1, contacts2);
}
This task can be resolved using Stream API (allowing for joining more than 2 lists any of which may be null):
// AddressBook
public void joinContacts() {
allContacts = ContactHelper.joinContactLists(contacts1, contacts2);
}
// ContactHelper
public static List<Contact> joinContactLists(List<Contact> ... lists) {
return Arrays.stream(lists) // Stream<List<Contact>>
.filter(Objects::nonNull) // filter out null lists
.flatMap(List::stream) // convert to Stream<Contact>
.sorted() // sort
.distinct() // _and then_ remove duplicates
.collect(Collectors.toList());
}
contacts1.addAll(contacts2);
contacts1.sort((o1, o2) -> o1 < o2 ? o1 : o2);
contacts1.addAll(contacts2)
This adds all contacts2 to contacts1 and contacts1 List will have all the contacts.
Here u can replace o1 < o2 can be replaced with the logic u need to sort.
The easiest way to ensure, that you do not have duplicates in your ArrayList is to copy your list into a Collection that does not allow duplicates (for example a set) and then copy it back into the ArrayList you need. I would recommend to check out this post for this:
Answers to Question: I have an ArrayList, and I want to remove repeated strings from it. How can I do this?
Ultimately your problem could be answered the following way (using the code of mentioned blog post):
allcontacts.addAll(contacts1);
allcontacts.addAll(contacts2);
Set<Contact> set = new HashSet<>(allcontacts);
allcontacts.clear();
allcontacts.addAll(set);
Now you got rid of all duplicates and merged the ArrayLists contacts1 and contacts2 into allcontacts.
You now only have to sort allcontacts, which can be done like this (if Contact implements Comparable):
Collections.sort(allcontacts);
I want to get the model numbers from the list only
['brand: Samsung, model number: VA2210-MH, size: 21.5', 'brand: Philipe, model number: 244E1SB, size: 21.5']
And I set create attributes and getter and setter of all attributes(only model number will be shown) in Monitor
public class Monitor{
public String brand;
public String modelNumber;
public double size;
public Monitor(String brand, String modelNumber, double size){
this.brand = brand;
this.modelNumber = modelNumber;
this.size = size;
}
public void setModelNumber(String amodelNumber){
modelNumber = amodelNumber;
}
public String getModelNumber(){
return modelNumber;
}
}
so I create a list and add the information into the list
and a method to create a set with model number by the method modelNumberSet()
import java.util.*;
public class ComputerShop{
private List<Monitor> monitorList = new ArrayList<>();
public void addMonitor(String brand, String modelNumber, double size){
Monitor newMonitor = new Monitor(brand, modelNumber, size);
monitorList.add(newMonitor);
}
public Set<Monitor> modelNumberSet(){
Set<Monitor> NewSet = new HashSet<>();
for (Monitor m : monitorList) {
NewSet.add(m.getModelNumber());
}
return NewSet;
}
}
I hope the model number will be added into a new set, the output looks like
[VA2210-MH, 244E1SB]
So I use for loop to incase I will add more information in the future, but the error comes out when I use add(). Why the array cannot be added into the new set? Am I using the wrong function?
Is there a better solution I should use?
Change Set<Monitor> to Set<String>. You are adding model numbers to the set and their types are String. You are trying to put a String where a Monitor is expected. Square peg in a round hole.
Fix the modelNumberSet() method as follows:
public Set<String> modelNumberSet(){
Set<String> newSet = new HashSet<>();
for (Monitor m : monitorList) {
newSet.add(m.getModelNumber());
}
return newSet;
}
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
Hey im using a hashmap of string and flights to create a flight store called planeStore. So then i made another store(Airline store) also using a hashmap. I put the planeStore into the AirlineStore. But i cant get the airlines printing out with the planes.
I thought by putting string airlineName into Airlines constrcutor. And passing in "Plane Name" When creating Airline airline = new Airline("PlaneName"); that this would work but it hasnt.
here is my code:
Airline
import java.util.HashMap;
public class Airline
{
private String airlineName;
private HashMap<String, PlaneStore> map;
public Airline(String airlineName)
{
this.airlineName = "";
map = new HashMap<String, PlaneStore>();
}
public void add(PlaneStore plane)
{
map.put(airlineName, plane);
}
public void remove(String flight)
{
map.remove(flight);
}
public void printPlane()
{
System.out.println("\n********Flight List********");
for (PlaneStore plane: map.values()) {
//System.out.println(plane);
// class
// or:
System.out.println(airlineName);
System.out.println(plane.toString());
}
}
}
plane.toString is the toString of the PlaneStore:
public String toString() {
return "PlaneStore [airlineName=" + airlineName + ", planeMap="
+ planeMap + "]";
}
MainApp
import java.util.Scanner;
public class MainApp
{
private Scanner keyboard = new Scanner(System.in);
public static void main(String[] args)
{
new MainApp().start();
}
public void start()
{
Airline airline1 = new Airline("AerLingus");
Airline airline2 = new Airline("Ryan Air");
PlaneStore planeStore = new PlaneStore("Aer Lingus");
PlaneStore planeStore2 = new PlaneStore("Ryan Air");
Flight p1 = new Flight("Aer Lingus","A01", 150.5, 10.5, 500, Flight.AIRPLANETYPE.AIRBUS);
Flight p2 = new Flight("Aer Lingus","B01", 50.3, 1.5, 91, Flight.AIRPLANETYPE.CORPORATE);
Flight p3 = new Flight("Aer Lingus","C01", 12.2, -3.1, 56, Flight.AIRPLANETYPE.AIRBUS);
Flight p4 = new Flight("Ryan Air","D01", 10.5, 1.5, 430, Flight.AIRPLANETYPE.PRIVATE);
Flight p5 = new Flight("Ryan Air","E01", 0.3, 2.1, 101, Flight.AIRPLANETYPE.CORPORATE);
Flight p6 = new Flight("Ryan Air","F01", 2.2, -3, 291, Flight.AIRPLANETYPE.AIRBUS);
planeStore.add(p1);
planeStore.add(p2);
planeStore.add(p3);
planeStore.print();
airline1.add(planeStore);
airline1.add(planeStore);
airline1.add(planeStore);
airline1.printPlane();
planeStore2.add(p4);
planeStore2.add(p5);
planeStore2.add(p6);
airline2.add(planeStore2);
airline2.add(planeStore2);
airline2.add(planeStore2);
airline2.printPlane();
}
}
Your Airline construtor receives a String argument but you are not assignment the instance variable airlineName of the class Airline to this argument. You are just making airlineName set to "".
public Airline(String airlineName)
{
this.airlineName = "";
map = new HashMap<String, PlaneStore>();
}
you mean:
public Airline(String airlineName)
{
this.airlineName = airlineName;
map = new HashMap<String, PlaneStore>();
}
Looking further in your code, it appears that each Airline class will have an map but you only add a key to this map, along with the values PlaneStore. So it appears that you will never have two or more keys for each map on each Airline class. Therefore, there is no point in using map, you can use instead an ArrayList.
If I understand correctly your objective you can simplify your AirLine class to something like this:
public class Airline
{
private String airlineName; // Name of the company
private ArrayList <PlaneStore> planeStore;
public Airline(String airlineName)
{
this.airlineName = airlineName;
map = new ArrayList<PlaneStore>();
}
public void add(PlaneStore plane){ planeStore.add(plane);}
public void printPlane()
{
System.out.println(airlineName);
System.out.println("\n********Flight List********");
for (PlaneStore plane: planeStore)
{
System.out.println(plane.toString());
}
}
}
You're setting airlineName to "" rather than the String that you pass into it throught the constructor.
Once you change the code to read this.airlineName = airlineName; you should be ok with this part.
By the way it still looks like you are using the same key for every plane you add. This will constantly overwrite the last plane you added with the new one. If you want to be able to print out all of the planes, you need to give them each a unique key. Otherwise this won't work.