I need to make a list of people and their time of arrival to a party, and when ever they leave I need to take them off this list. (the party maximum is 150)
Set would provide me that in no case I would add the same person twice.
List would provide me flexibility to start the list with few spaces (in case no one shows up).
Arrays (not sure what they provide) but I used them more often.
My idea was either to create 2 arrays one with names and what with times. When someone comes in, I save name in one and time on the other. When he/she leaves I search for his/her name, delete it and use the same index to delete the time on the other array.
A list could have one array of 2 elements, and then I will only need to add it in one location but searching would be a TINY more complicated.
Or maybe I am complicating this too much?
Map implementation:
public final class Person
{
... remainder left to the student ...
}
Map<Person, Date> currentPartyAttendees; // date is arrival time.
Set implementation:
public final class PartyAttendee
{
... person details ...
Date arrive;
int hashcode()
{
... use Apache HashCodeBuilder ...
}
boolean equals(Object other)
{
... implementation left to student. Use Apache EqualsBuilder ...
}
}
Set<PartyAttendee> currentPartyAttendees;
Using a HasMap would suit your purpose, as you can use the person's name as a key to add and retrieve the entry for the person, and it offers constant time performance, so regardless of how large the set grows, the performance should remain consistent.
The way you've described your use-case, why not consider the HashMap, or some other Map based implementation?
Unless of course, there's a binding for you to use a List [or similar] based data structure.
Just use a List<> and a Data structure the represents guest.
Subclass List to mark the arrival and departure time and add/remove methods. You can also use set, but then you'll have to generate a hashCode and equals method. I'm not sure you want to do that, cause people may have the same names (unless you have other data like SSN, bday, middle name etc)
public Class Guest{
private String firstName, lastName;
private long arrivalTime, departureTime;
....
}
public class MyGuests extends ArrayList<Guest>{
#Overide
public void add(Guest g){
//record arrival time here
super.add(g)
}
#Overide
public void remove(Guest g){
//record departure time here
super.remove(g);
}
}
I think you can use arrays as well, and, instead two arrays, use an arrays of 'Person' model, that holds the name of the person, arrive time and leave time. Before you insert on array, you can verify if the list already contains this person.
ps: don't forget to overwrite equals() and hashCode() in your model
LinkedHashMap - a container of key-value pairs that maintains the order of their insertion. The key would be the person (a simple String or a designated class), the value would be the time of arrival, e.g. a Date.
Related
I have been working with the following class named City
#ToString
#AllArgsConstructor
public class City {
Integer id;
String name;
}
and tried to convert it to a record called CityRecord as
record CityRecord(Integer id, String name) {} // much cleaner!
But moving to such a representation, one of our unit tests starts failing. The tests internally deal with a list of cities read from a JSON file and mapped to an object further counting the cities while grouping them under into a Map. Simplified to something like:
List<City> cities = List.of(
new City(1, "one"),
new City(2, "two"),
new City(3, "three"),
new City(2, "two"));
Map<City, Long> cityListMap = cities.stream()
.collect(Collectors.groupingBy(Function.identity(),
Collectors.counting()));
The above code asserted true to contain 4 keys and each accounting for 1 of its occurrence. With the record representation, there are no more than 3 keys in the resulting Map. What is causing this and what should be the way to go around this?
Cause
The reason behind the behavior observed is as documented in java.lang.Record
For all record classes, the following invariant must hold: if a record
R's components are c1, c2, ... cn, then if a record instance is copied
as follows:
R copy = new R(r.c1(), r.c2(), ..., r.cn()); then it must be the case that r.equals(copy).
In short, your CityRecord class now has an equals(and hashcode) implementation that compares the two attributes and ensure if they are equal the record consisting of those components are also equal. As a result of this evaluation, the two record objects with the same attributes would be grouped together.
The result, therefore, would be correct to infer/assert that there should be three such keys with the one having id=2, name="two" counted twice.
Immediate Remedy
An immediate temporary solution to this would be to create a custom(flawed - reason explained later) equals implementation within your record representation as well. This would look like:
record CityRecord(Integer id, String name) {
// WARNING, BROKEN CODE
// Does not adhere to contract of `Record::equals`
#Override
public boolean equals(Object o) {
return this == o;
}
#Override
public int hashCode() {
return System.identityHashCode(this);
}
}
Now that the comparison would be between two objects as in while using the existing City class, your tests would just work fine. But you must note the caution below before using any such remedy.
Caution
As the JEP-359 reads, Records are more like "data carrier" and while choosing to migrate your existing classes, you must be aware of the standard members acquired by a record automatically.
Planning to migrate one must be aware of the complete details of the current implementation, such as in the example you quoted while you've grouped by City, there should be no reason to have two cities with same id and name data to be listed differently. They should be equal, it should be the same data after all repeated twice and hence the correct counts.
In which case, your existing implementation if representing a data model could be rectified to match the record in a way by overwriting the equals implementation to account for comparing the individual attributes as well which is where the immediate remedy stated above is contradictory and should be avoided.
I have an object Person with the following fields:
firstName, secondName, age, nationallity, address, phoneNr.
And the list: ['John', 'Smith', '35', 'american', 'San Francisco', '+0324 235 327'].
I would like to put the values of the list into the object Person, without using the classic method of setting each value.
I want to avoid this:
person.setFirstName(list.get(0));
person.setSecondName(list.get(1));
person.setAge(list.get(2));
person.setNationallity(list.get(3));
person.setAddress(list.get(4));
person.setPhoneNumber(list.get(5));
My object has more fields than the ones I've put here as example (about 15), and I want to avoid writting a lot of code.
So my question is there a more elegant way of dumping all the values from the list into the object? I was thinking that in Java 8 maybe is there something but so far I haven't found anything.
There is no way to dump all values from the list into object, but you can add a new contructor in your Person Class, with a list as parameter like this :
public Person(List<String> list) {
this.firstName(list.get(0));
this.secondName(list.get(1));
this.age(list.get(2));
this.nationallity(list.get(3));
this.address(list.get(4));
this.phoneNumber(list.get(5));
}
and the call will be like :
Person person = new Person(list);
The other answer is good, there is one trick that can make it easier to work with though. This is especially relevant if there are a large number of entries such as the 15 mentioned in the question:
public Person(List<String> list) {
int index = 0;
this.firstName(index++);
this.secondName(index++);
this.age(index++);
this.nationallity(index++);
this.address(index++);
this.phoneNumber(index++);
}
Now you can add things to the list in any position or change the order or otherwise adjust it and don't have to manually update all the indexes. It also removes the risk of human error in accidentally getting an index wrong - although you do still need to get all the fields in the right order.
How do I make my code to add identical objects to a SET? I guess I will have to do something with hashcode() or equal() functions.
Class Order {
private id;
private Set<Discount>;
}
Class Discount {
private id;
private Long amount;
}
Now if I try to save two discounts of $1 each, the SET only shows one discount. When hibernate saves it, discounts will have different IDs, but they are same as of now. Don;t want to change the definition of Order class, as it's a big project and changes will be endless
According to the JavaDoc for the Set interface, a set is not allowed to contain duplicate identical elements (as defined by equals and hashcode). While this will work fine when hibernate saves the discounts (since you said the ids will be different), the ids are the same right now, so what you are trying to accomplish is not possible without doing things that future people who will be stuck maintaining your code will hate you for.
Since you do not desire to change the Order class, your best recourse is to retroactively change the ids on your discounts to be unique.
You cannot add identical objects to a set, because that is the point of a set. A set contains unique elements. You would be better off using a list or a map.
I am trying to build a "flat file reader." These files will have several related columns, such as "Customer Name", "Telephone," etc, but the column number will be different for each flat file; also, some flat files will have columns that others don't.
I want each of these different files to be readable by the FlatFileReader class. So I created an enum for the first flat file, where the value is an index for an array.
enum Columns { NAME, TELEPHONE, PAYMENT }
...
String[] columns = new String[3];
columns[0] = line.substring(0,29); //Name
columns[1] = line.substring(30,36); //Telephone
columns[2] = line.substring(37); //Payment
So in order to get, for example, a name from the flat file, FlatFileReader would call the method:
file.get (Columns.NAME);
and FlatFileA would look for index 0. There's going to be a wide variety of flat file classes, and I would like for each to inherit the same enum so that it's consistent; the issue is that some files won't have certain columns. So I can't do NAME, TELEPHONE, PAYMENT in the parent class (or interface) if FlatFileB doesn't have a TELEPHONE column.
How could I solve this problem? Is this how an EnumSet is used? Could each child class create an EnumSet and only add the constants it needs? If I created an EnumSet and only added NAME and PAYMENT, would PAYMENT now have a value of 1 (inside the EnumSet) or would it still have the value of 2?
EnumSet is just another implementation of the Set interface. Implementing the Set interface means it behaves just as much as a Set as any other implementation. The difference is in performance, accepted values and iteration order.
The benefit of the EnumSet is speed, the downside is that EnumSets can only have enum constants as members. Since each enum constant has a zero-based ordinal(), the EnumSet uses a bitstring representation, where each bit represents the presence/absence of an element in the set. Choosing EnumSet makes contains(All), add(All), remove(All) and retain(All) run much faster than for TreeSet and HashSet.
And no, an enum constant never changes its ordinal() (though I'm not sure whether that was what you meant).
I would suggest an ArrayList as your columns are in a sequence. I would further recommend you use an ArrayList of objects that encapsulate a Column along with details about how to gather the column from the records.
class Field {
Columns col;
int start;
int length;
}
ArrayList<Field> file1Record = new ArrayList<Field>();
// You could calculate the 0 and 29 on the fly.
file1Record.add(new Field(Columns.NAME, 0, 29));
...
I have 65000 records of employees in a database . i am retreiving all the records and storing as employee object in a list as a cache. when customer enters the emp id in the browser , the record should be fetched from the list on one condition , without looping through the list. how can we acheive it.
using indexOf(Object ) we can acheive ,by implementing equals method , but what business logic should go in that.kindly let me know your views.
class Employee
{
private int id;
private String name;
Private String address;
public void setAddress (){}
public void setId(){}
public void setName(){}
// simillarly getMethods
}
1) I would implement a cache based on a hashmap rather than a list:
Map cache = new HashMap<Integer, Employee>();
This way you can retrieve an Employee object by a given ID very efficiently.
Additionally, I wouldn't add a setter for the employee id, since it can corrupt the mapping. Consider setting the id through a constructor parameter only.
--EDIT--
If you MUST use a list:
2) You may want to sort it first. This will allow performing a binary search (See Collections.binarySearch(..) methods). This requires implementing a Comparator or the Comparable interface, in order to define an ordering between the Employee objects. Also, you will have to create a dummy Employee object with the required id each time you want to perform the search.
3) If performance is not an issue, simply use List.indexOf(..). This requires implementing the equals(..) method in the Employee class.
4) In order to do it really without loops, you can create a sparse list, containing Employee with id N at index N. This is only feasible if the Employee id value range is not too big. The benefit is an optimal retrieval time.