I am trying to return a collection containing connections in a network that starts or ends at a specific station. I am having trouble figuring out how to return it and take the station parameter. Also is having the creation of the hashMap in the method the right way to do it, or should it be created outside of it?
It is giving me the error incompatible types: Connection cannot be converted to Collection<Connection> for the return statement
CODE:
/**
* Return a Collection containing all the Connections in the network that
* start or end at a specified station
*
* #param station Station to/from which the Connection should run
*
* #return a Collection containing all the connections that start or end at
* the specified station
*/
#Override
public Collection<Connection> getConnectionsFrom(Station station) {
Map<Station, Connection> stationConnectionFrom = new HashMap<Station, Connection>();
return stationConnectionFrom.get(station);
}
Only one Connection is being returned. You can change your return type to:
public Connection getConnectionFrom(Station station) {
Map<Station, Connection> stationConnectionFrom = new HashMap<>();
return stationConnectionFrom.get(station);
}
In your case, the map being empty, this will always return null.
If you can't change method signature, you can do:
#Override
public Collection<Connection> getConnectionsFrom(Station station) {
Map<Station, Connection> stationConnectionFrom = new HashMap<Station, Connection>();
return Collections.singletonList((stationConnectionFrom.get(station));
}
Related
Q: Given a log file with API names, start and end timestamps, write a program that prints the average latency for each API call.
It was asked in google interview, my solution got rejected. So, want to know how can this be solved in optimized way.
$ cat log
get_foo start 2222222100
get_foo end 2222222150
get_bar start 2222222200
get_foo start 2222222220
get_bar end 2222222230
get_foo end 2222222250
solution :
$ cat log | myprog
get_foo: average = 40
get_bar: average = 30
I suggest you to breakdown the process to simplify the complexity of your problem.
Here could be a good starting point about how to define the process :
Done in Java, it could lead to this :
public class Program {
// The HashMap which contains api keys and object wrappers associated to it.
private Map<String, ApiCall> hashMap = new HashMap<>();
/**
* getHashMap
* Setter of the hashMap which contains api keys and object wrappers
* associated to it.
* #return
*/
public Map<String, ApiCall> getHashMap() {
return hashMap;
}
/**
* setHashMap
* Getter of the hashMap which contains api keys and object wrappers
* associated to it.
* #param hashMap
*/
public void setHashMap(Map<String, ApiCall> hashMap) {
this.hashMap = hashMap;
}
/**
* getNewApiCall
* #return a new ApiCall wrapper object
*/
public ApiCall getNewApiCall() {
return new ApiCall();
}
/**
* main
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
Program app = new Program();
// Arbitrary path to test with my environment
String path = args.length > 1 ? args[0] : "/home/user/test";
// Read all lines from your log file
List<Object> lines = Arrays.asList(
Files.lines(
Paths.get(new File(path).getPath())
).toArray()
);
for (Object o:lines) {
String s = o.toString().trim();
// If it's not and empty line
if (!s.isEmpty()) {
/*
* Split the lines into array with
* [0] = api_name, [1] start or end, [2] timestamp
*/
String[] values = s.split(" ");
// Add the API call to a hashmap without any value
app.getHashMap().put(values[0], null);
// Here you have all name of calls of your API
/*
* Now for each api call, wrap it into an object that will
* handle the average computation, the array of start
* timestamps and the array of end timestamps
*/
ApiCall apiCall = app.getHashMap().get(values[0]);
// Create and object for wrapping starting and ending timestamps
if (apiCall == null) {
apiCall = app.getNewApiCall();
}
/*
* If the line is a start then parse the last value to a long
* and add it to the object wrapper to further compute for the
* average
*/
if (values[1].equals("start")) {
apiCall.addStart(Long.parseLong(values[2]));
}
/*
* Else it is a end timestamp then parse the last value of the
* line to a long and add it to the object wrapper to further
* compute for the average
*/
else {
apiCall.addEnd(Long.parseLong(values[2]));
}
// Add the new incremented object wrapper to the API key
app.getHashMap().put(values[0], apiCall);
}
}
/*
* Stream hashmap entries (API keys) and print the key and the average
* value for each
*/
app.getHashMap().entrySet().forEach(
ks -> System.out.println(
ks.getKey()+" average="+ks.getValue().getAverage()
)
);
}
}
The class leading to object to wrap starting and ending timestamps for a specific API call for further computation.
/**
* ApiCall
* Class allowing to collect starting timestamps and ending timestamp for
* an API call. Compute the average on each addition.
* #author user
* #since 12 sept. 2019
*/
public class ApiCall {
private List<Long> start;
private List<Long> end;
private double average;
public ApiCall() {
start = new ArrayList<>();
end = new ArrayList<>();
}
public void addStart(Long l) {
start.add(l);
setAverage(computeAverage());
}
public void addEnd(Long l) {
end.add(l);
setAverage(computeAverage());
}
public double getAverage() {
return this.average;
}
private void setAverage(Double average) {
this.average = average;
}
private double computeAverage() {
return
(
end.stream().mapToLong(Long::longValue).average().orElse(0.0)
- start.stream().mapToLong(Long::longValue).average().orElse(0.0)
);
}
}
I just did this to give you a starting point about how to do. Don't copy/paste because the code is badly written and there is surely errors about the average computation as you can see in the output :
get_bar average=2.22222223E9
get_foo average=2.22222225E9
Hope it helps.
I need to add an Object to an ordered ArrayList depending on an attribute inside of the Object. I know how to use the .add method to add the object but I don't know how to search for the right place for it using the compareTo() method. And also I need to remove an Object from the ArrayList if the Object contains a certain String but I cant figure out how to access the Object attributes from the ArrayList.
Realtor Object
/**
* Constructor for Realtor object using parameter
* #param readData - array of data from line
*/
public Realtor(String[]readData){
licenseNumber = readData[2];
firstName = readData[3];
lastName = readData[4];
phoneNumber = readData[5];
commission = Double.parseDouble(readData[6]);
}
RealtorLogImpl
public class RealtorLogImpl {
private ArrayList<Realtor> realtorList;
/**
* Add Realtor object to ordered list
* #param obj - Realtor object
*/
public void add(Realtor obj){
//needs to be added into correct place depending on Realtor licenseNumber
realtorList.add(obj);
}
/**
* Delete Realtor object from list if license matches
* and return true if successful
* #param license
* #return
*/
public boolean remove (String license){
//need to remove Realtor with specific licenseNumber and return true if successful
}
I'm assuming you are using java 8. Some of these things have not been implemented in java 7 so keep that in mind.
First, to remove the items I would recommend using the removeif() method on the arraylist. This takes a lambda expression which could be something like x -> x.getString().equals("someString").
Second, You could add the object to the array then simply sort the array afterwards. You would just have to write a comparator to sort it by.
Here is some basic code; I have no compiler here, so you might find small errors/typos.
I'm sure there are better classes you can use instead of managing your own ordered list.
To insert:
public bool add(Realtor obj) {
int idx = 0;
for (Realtor s : realtorList) {
if (s.licenseNumber.equals(item.licenseNumber)) {
return false; // Already there
}
if (s.licenseNumber.compareTo(item.licenseNumber) > 0) {
orderedList.add(idx, item);
return true; // Inserted
}
idx++;
}
orderedList.add(item);
return true; // Appended
}
To delete:
public bool deleteItem(String license) {
int idx = 0;
for (Realtor s : realtorList) {
if (s.licenseNumber.equals(license)) {
realtorList.remove(idx);
return true; // Removed
}
}
return false; // Not found
}
To answer your question check the following snippet (requires Java 8) and adapt on your demand:
public static void main(String[] args) {
final List<String> list = new ArrayList<>();
list.add("Element 1");
list.add("Element 2");
list.add("Element 3");
/*
* Insert at a specific position (add "Element 2.5" between "Element 2" and "Element 3")
*/
Optional<String> elementToInsertAfter = list.stream().filter(element -> element.equals("Element 2")).findFirst();
if(elementToInsertAfter.isPresent()) {
list.set(list.indexOf(elementToInsertAfter.get()) + 1, "Element 2.5");
}
/*
* Remove a particular element (in this case where name equals "Element 2")
*/
list.removeIf(element -> element.equals("Element 2"));
}
#add(element) just adds an element to the list. In case of an ArrayList it's added at the end. If you want to insert an element at a particular position you need to use #set(index,element)
But instead of inserting your element at a particular position manually you should maybe use a comparator instead. See java.util.List.sort(Comparator<? super E> e)
Scenario:
I've two reports: Main Report (let's call it, A) and sub-report (let's call it, B).
Report A contains sub-report B at the detail band, so sub-report B is displayed for each element at the Report A datasource. Sub-report B also returns a variable to the Main report A.
What I want is to sum those return values from sub-report B and totalize them at the Main report summary.
To do that, I have tried to create a new report variable that sum those returns values... Something like this:
However, I've found that such variables expression are always evaluated before the band detail is rendered, so I always miss the first sub-report return value...
Sadly, the evaluation time (as this link says) cannot be changed on those kind of variables, so I'm stuck...
After been struggling with this for some hours... and searching the internet for a solution... I came with a Workaround (the enlightening forums were these ones: one and two).
First, you need to define a java Class Helper that allows you calculate some arithmetic operation, in my case a Sum operation. I defined these classes:
package reports.utils;
import java.util.Map;
/**
* Utility that allows you to sum Integer values.
*/
public class SumCalculator {
/**
* Stores a map of {#code SumCalculator} instances (A Map instance per thread).
*/
private static final ThreadLocalMap<String, SumCalculator> calculatorsIndex = new ThreadLocalMap<>();
/**
* The sum total.
*/
private int total = 0;
/**
* No arguments class constructor.
*/
private SumCalculator() {
super();
}
/**
* Instance a new {#code SumCalculator} with the given ID.
*
* #param id {#code SumCalculator}'s ID
* #return the new {#code SumCalculator} instance
*/
public static SumCalculator get(String id) {
Map<String, SumCalculator> map = calculatorsIndex.get();
SumCalculator calculator = map.get(id);
if (calculator == null) {
calculator = new SumCalculator();
map.put(id, calculator);
}
return calculator;
}
/**
* Destroy the {#code SumCalculator} associated to the given ID.
*
* #param id {#code SumCalculator}'s ID
* #return {#code null}
*/
public static String destroy(String id) {
Map<String, SumCalculator> map;
map = calculatorsIndex.get();
map.remove(id);
if (map.isEmpty()) {
calculatorsIndex.remove();
}
return null;
}
/**
* Resets the {#code SumCalculator} total.
*
* #return {#code null}
*/
public String reset() {
total = 0;
return null;
}
/**
* Adds the given integer value to the accumulated total.
*
* #param i an integer value (can be null)
* #return {#code null}
*/
public String add(Integer i) {
this.total += (i != null) ? i.intValue() : 0;
return null;
}
/**
* Return the accumulated total.
*
* #return an Integer value (won't be null, never!)
*/
public Integer getTotal() {
return this.total;
}
}
package reports.utils;
import java.util.HashMap;
import java.util.Map;
/**
* Thread Local variable that holds a {#code java.util.Map}.
*/
class ThreadLocalMap<K, V> extends ThreadLocal<Map<K, V>> {
/**
* Class Constructor.
*/
public ThreadLocalMap() {
super();
}
/* (non-Javadoc)
* #see java.lang.ThreadLocal#initialValue()
*/
#Override
protected Map<K, V> initialValue() {
return new HashMap<>();
}
}
Second, at your jasper report, you need to define four text fields:
1) A text field that iniatializes your calculator; it should be (ideally) at the title section of the report and should have an expression like this: SumCalculator.get("$V{SUB_REPORT_RETURN_VALUE}").reset(). This text field should have the evaluation time: NOW.
2) A text field that calls the increment function (i.e. SumCalculator.get("$V{SUB_REPORT_RETURN_VALUE}").add($V{SUB_REPORT_RETURN_VALUE}). This text field will reside at your detail band, after the subreport element; and it should have the evaluation time: BAND (this is very important!!)
3) A text field that prints the calculator total. This text field will reside at your summary band, it will evaluate to NOW. Its expression will be: SumCalculator.get("$V{SUB_REPORT_RETURN_VALUE}").getTotal()
4) A text field that destroy the calculator. This text field will also reside at your summary band and must appear after the text field 3. The text field should have an expression like: SumCalculator.destroy("$V{SUB_REPORT_RETURN_VALUE}"). This text field should have the evaluation time: NOW.
Also, the text fields: 1, 2, and 4, should have the attribute "Blank when Null", so they will never be printed (that's why those java operations always return null).
And That's it. Then, your report can look something like this:
if i understand the problem, you can not summarize the amount returned by the sub report in the main report, i had the same problem and i solved in this way.
1.- Create a class which extends from net.sf.jasperreports.engine.JRDefaultScriptlet. and override the method beforeReportInit()
this is the code from this class.
package com.mem.utils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import net.sf.jasperreports.engine.JRDefaultScriptlet;
public class SumarizacionSubtotales extends JRDefaultScriptlet {
private final Log log = LogFactory.getLog(getClass());
private Double total;
public Double getTotal() {
return total;
}
public Double add(Double cantidad) {
if(log.isDebugEnabled())log.debug("AGREGANDO LA CANTIDAD : " + cantidad);
this.total += cantidad;
return cantidad;
}
#Override
public void beforeReportInit() throws JRScriptletException {
if(log.isDebugEnabled())log.debug("beforeReportInit");
total = 0.0D;
}
}
2.- add your project's jar in your ireport's classpath.
3.- Replace the class of the REPORT scriptlet.
in the properties with your class.
3.- add in the group footer where you want to print the value returned by the sub-report a textfield with the following expression.
$P{REPORT_SCRIPTLET}.add( $V{sum_detalles} )
In this case $V{sum_detalles} is a variable in the main report which contains the value returned by the sub-report.
4.- Add in the Last page footer another textfield with the following expression.
$P{REPORT_SCRIPTLET}.getTotal()
first off this is an assignment so I'm more looking for help then coded answers (don't want to cheat!). My assignment is to create a program that processes a train/railway network of stations. The section i'm stuck on adds the stations, their connections, and returns these connections as an Array List of Strings. I've included below the code I have so far, and also an extract from the assignment (related to the section I'm on now). I've been struggling with this bit all weekend, so any help would be hugely appreciated.
It's only the implementation of the interface I need to edit, the "MyNetwork" class. I just feel I've been going in circles, and may not have even gotten off on the right foot?
From the assignment;
Create a class MyNetwork that implements the Network interface.
The getConnections method of this class should return an array containing only those stations directly connected to the fromStation argument.
Hint 1: you can do this using a HashMap, with the keys being Strings (representing stations) and the values being ArrayLists of Strings (representing the stations to which there is a direct connection).
Hint 2: Although the getConnections method returns an array of Strings, it would be better for the values in the HashMap to be ArrayLists of Strings
The Interface;
public interface Network {
/**
* Add a station to the network.
* #param station The station to be added.
*/
public void addStation(String station);
/**
* Add a direct connection from one station to another.
* #pre both fromStation and toStation have already been added by the method
* addStation.
* #param fromStation The station from which the connection begins.
* #param toStation The station at which the connection ends.
*/
public void addConnection(String fromStation, String toStation);
/**
* Get a list of all stations directly connected to a given station.
* #pre fromStation has been added to the network by the method addStation.
* #param fromStation
* #return A list of all the stations to which there is a direct connection
* from fromStation.
*/
public String[] getConnections(String fromStation);
/**
* Search for a station in the network.
* #param station Station to be searched for,
* #return true if the Station exists in the network, false otherwise.
*/
public boolean hasStation(String station);
/**
* Get all stations in the network.
* #return An array containing all the stations in the network, with no
* duplicates.
*/
public String[] getStations();
The Implementation:
public class MyNetwork implements Network {
#Override
public void addStation(String station) {
ArrayList<String> Stations = new ArrayList<>();
Stations.add(station);
}
#Override
public void addConnection(String fromStation, String toStation) {
Map<String,String> Connections = new HashMap<>();
Connections.put(fromStation, toStation);
}
#Override
public String[] getConnections(String fromStation) {
return null; // dummy value!
}
#Override
public boolean hasStation(String station) {
return false; // dummy value!
}
#Override
public String[] getStations() {
return null; // dummy value!
}
}
Your network needs to have a state, using one or several instance field(s).
As is, it doesn't have any state. Each method creates a local variable of type List or Map, adds something to this List or Map, and returns. So the List or Map directly goes out of scope and is garbage collected.
private Map<String, List<String>> stations = new HashMap<>();
// now all your methods should use the above map.
See http://docs.oracle.com/javase/tutorial/java/javaOO/classes.html
I have the following code. However I am doubting about if it is the right way to implement it or not.
What I mean is: in the collection framework there are many data structures to use and creating the class (MemberList) to manage the aggregations of many members can be implemented using ArrayList, LinkedList, priority queue ...
I would like to use a data structure that fits with my needs, and that has the least Big O possible when it comes to searching, sorting, deleting, adding, modifying and deleting.
public class MemberList{
/**
*a list of accounts existing in the database
*/
private static List<Member> members = new ArrayList<Member>();
/**
* add a member to our member list
* #param m the member to be added
*/
public static void Add(Member m)
{
members.add(m);
/**
* delete a member from our member list
* #param m the member to be deleted
*/
public static void Delete(Member m)
{
Iterator<Member> it = members.iterator();
while(it.hasNext())
{
if(m.equals(it.next()))
{
it.remove();
}
}
}
/**
* Search for a specific member in the member list
* #param m the member that needs to be found
* #return the reference of the object Member
* #throws UserNotFoundExeption whether the member was not found in the list
*/
public static Member Search (Member m) throws UserNotFoundExeption
{
Iterator<Member> it = members.iterator();
while(it.hasNext())
{
if(m.equals(it.next()))
{
return it.next();
}else{
UserNotFoundExeption ex = new UserNotFoundExeption(it.next().getUsername());
throw ex;
}
}
return null;
}
/**
* The login method enables checking whether the login was made successfully or not. if not, it can throw two
* exceptions to handle the errors
* #param member
* #return
* #throws UserNotFoundExeption
* #throws FailedLoginException
*/
public static boolean login (Member m)
throws UserNotFoundExeption,FailedLoginException {
try{
Member member = Search(m);
if (!m.authenticate(member.getPassword()))
{
FailedLoginException ex2 = new FailedLoginException (member.getPassword());
throw ex2;
}
else
{
return true;
}
}catch(UserNotFoundExeption ex){
throw ex;
}
}
/**
* this behavior modify attributes of the corresponding class
* #param <T> this generic helps to accept any type of parameter change, hence we can change any type
* #param m this is the member that need to change his information
* #param choice the choice of which information to change
* #param change the new change on the member attribute
* #throws UserNotFoundExeption
*/
public static <T> void Modify(Member m, int choice, T change) throws UserNotFoundExeption
{
try{
Member member = Search(m);
switch(choice)
{
case 1:
member.setUsername((String)change);
break;
case 2:
member.setPassword((String)change);
break;
case 3:
member.setCommunity((Community)change);
break;
}
}catch(UserNotFoundExeption ex){
throw ex;
}
}
/**
* display the member list objects information
*/
public static void Display()
{
Iterator<Member> it = members.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
/**
* Sort objects in the list
*/
public static void Sort()
{
Iterator<Member> it = members.iterator();
Member[] Members_Array = members.toArray(new Member[members.size()]);
Member temp;
for(int i = 0; i<members.size(); i++)
{
for(int j = 0; j < members.size() - (i+1); j++)
{
if(Members_Array[j].compareTo(Members_Array[j+1]) > 0)
{
temp = Members_Array[j];
Members_Array[j] = Members_Array[j+1];
Members_Array[j+1] = temp;
}
}
}
}
}
Thank you!
This question is too broad, and "the right way to use collections in Java" is also a philosophical question, so it cannot be scientifically answered.
Specifically to your case, depending on the pool of your members, you probably don't want to iterate over them when you need to pull a member out. I would recommend you use something like a HashMap<String,Member>, where each member has an identifiable unique key (a username for instance). This will grant you O(1) access speed and allow you to iterate when you need it using .values().
You can use a HashMap like so:
// This is how you create a hash map:
HashMap<String,Member> members = new HashMap<String,Member>();
// This is how you add an object to it. It is slower than lists,
// but since reading happens far often, it pays off.
members.put("ben", new Member());
// This is how you access an object in the hash map.
// Accessing a hash map is O(1).
Member member = members.get("ben");
// This is how you remove an object from the hash map.
// Removing an object is also O(1)
members.remove("ben");
// Hash maps are also iterable
for(Member member : members.values()) {
}
I would use array list if you dont want to use JDBC.
But later if your project going to growe, you have to use JDBC.