I have a customer object with three properties: last name, first name, and SIN number
If the user enters the customer's last name and first name, and the object is found in the arraylist, the objects gets removed.
private static void deleteCustomer (String lastName, String firstName, List<Customer> accounts)
{
for (int i = 0; i < accounts.size(); i++)
{
accounts.get(i);
public int compare (Customer c1, Customer c2)
{
Customer customerOne = (Customer) c1;
Customer customerTwo = (Customer) c2;
if (lastName.equals(CustomerOne.getLastName()) && firstName.equals(CustomerOne.getFirstName()))
{
}
}
}
}
If two customers have the same first and last name, the user is asked to enter the SIN number, that's why I have the compare method. I'm not sure what to do after this.
Updated method:
public static void deleteCustomer (String lastName, String firstName, List<Customer> accounts)
{
for (Iterator<Customer> iterator = accounts.iterator(); iterator.hasNext();)
{
Customer customer = iterator.next();
if(lastName.equals(customer.getLastName()) && firstName.equals(customer.getFirstName()))
{
iterator.remove();
}
}
}
This works, but it removes all customers with the same first and last name
If you simply wish to delete one customer as you have described in the question you should break the loop after you have found the correct customer and removed it:
iterator.remove();
break; // breaks the loop
But, since it seems as if there may be multiple customers with the same first+lastname the algorithm is not exactly bullet-proof. Maybe a customer id or similar should be used to distinguish between customers. In the case of a customer id the data structure to use should quite possibly be a Map<CustomerId, Customer>. Customers can then be quickly accessed via the id and you still can retrieve a collection of all customers by invoking the values() method.
In addition to this, if you don't want to modify the original List you can also use a Java 8 construct where you stream, filter and collect your data.
final List<Customer> newAccountList = accounts.stream()
.filter(c -> !(Objects.equals(c.getFirstName(), firstName) &&
Objects.equals(c.getLastName(), lastName)))
.collect(Collectors.toList());
The List above contains everything from the original List except for those entries where first+lastname matches.
Related
I have two list of type String and an object (consider Employee). String type list have employee codes. Here I need to check if Employee list have any object of code(attribute) saved in String. Below is my employee class
public class Employee {
public String code;
public String id;
// getters, setters and constructor
}
Here I am able to find whether employees have code saved in the given String List (employeeUserGrpCodes).
public static void main(String[] args) {
final List<String> employeeUserGrpCodes= Arrays.asList("ABCWelcome","ABCPlatinum","SuperEmployee");
List<Employee> empList=new ArrayList<Employee>();
Employee k1= new Employee("KCAEmployee","1");
Employee k2 = new Employee("ABCWelcome","2");
empList.add(k1);
empList.add(k2);
List<Employee> empListN = empList.stream().filter(i->employeeUserGrpCodes.stream().anyMatch(j->j.equalsIgnoreCase(i.getCode()))).collect(Collectors.toList());
List<String>newEmpList = empList.stream().map(a->a.getCode()).collect(Collectors.toList()).stream().filter(employeeUserGrpCodes::contains).collect(Collectors.toList());
if(!empListN.isEmpty() || !newEmpList.isEmpty())
{
System.out.println("Employee have employeeUserGrpCodes");
}
}
In the above code, both approaches are working that is List 'empListN' and List 'newEmpList'. Is it possible to do the same with the help of Predicates which I can easily put in String 'anymatch' like
Predicate<Employee> isEmpUserGroup = e -> e.getCode().equalsIgnoreCase(employeeUserGrpCodes.stream())
boolean isRequiredEmployee = empList.stream().anyMatch(isEmpUserGroup);
First of all for the purpose of knowing if Employee have employeeUserGrpCodes you don't need the two lists because is empListN is not empty newEmpList won't be as well, so we can use only of the two lists, and then, related with the use of the predicates, you are using them already in the filter expressions, you can have something like this for the empListN list:
Predicate<Employee> employeePredicate = e -> employeeUserGrpCodes.stream().anyMatch(c -> c.equalsIgnoreCase(e.getCode()));
List<Employee> empListN = empList.stream().filter(employeePredicate).collect(Collectors.toList());
You can notice that the Predicate is using another predicate as well
c -> c.equalsIgnoreCase(e.getCode())
So you can also replace the if condition and avoid using a temporary list if you test your predicate against the employee list like this:
if (empList.stream().anyMatch(employeePredicate)) {
System.out.println("Employee have employeeUserGrpCodes");
}
I have two different csv files having data on two different entities and I have to merge two different csv files to create one on the basis of sql join type equijoin and left join.
so I have created first entity as class name Customer having attributes:
int CustomerId ;
String CustomerName;
int OrderId;
And List of object of this class like:
Customer c1 = new Customer(CustomerId, CustomerName, OrderId);
1 million objects..
List<Customer> cust = new ArrayList<>();
cust.add(c1);
cust.add(c2);
so on to make list of 1 million object.
Similarly, I have created class of second entity Order having attributes:
int orderId;
String orderName;
Date orderdate;
Order o1 = new Order(orderId, orderName, orderdate);
so on 1 million object
List<Oder> order = new ArrayList<>();
Now I need to merge both the object on the basis of orderId and generate third object having result class having all the attributes from both the classes described above.
Please suggest me solution using java stream 8 to map both the streams of list to create inner join and left join type example in the third new result class.
Aside from the getters, your Customer class should have the following method:
public boolean orderMatch(Order order) {
//fixed the attribute name so it would be in camelCase
return orderId == order.getId();
}
Of course, this implies that Order has a getId() getter method to get its id attribute.
Finally, you'll need a CustomerExtended class.
class CustomerExtended {
int customerId ;
String customerName;
Order customerOrder;
public CustomerExtended(Customer customer, Order order) {
customerId = customer.getId();
customerName = customer.getName();
customerOrder = order;
}
}
Now, you can create a Function which would search for the corresponding Order and append it to a Customer:
Function<Customer,CustomerExtended> extendCustomer = (c) ->{
//I used the more descriptive name orderList instead of o1.
Optional<Order> order = orderList.stream()
.filter(c::orderMatch)
.findFirst();
if(order.isPresent()) {
return new CustomerExtended(c,order.get());
}
return null;
};
And then you can apply it to the Customer list through a map.
List<CustomerExtended> newCustomerList = customerList.stream()
.map(c -> extendCustomer.apply(c))
.collect(Collectors.toList());
EDIT: A few last notes
There should be some check that the ID numbers are not duplicate either when adding the objects to the lists, or when the lists are populated.
For semantic purposes, The Customer object as it is should be renamed CustomerOrder or be separated into an object only for customer info and an object which would store the relation between customer and order.
The case where an order is not found should be better handled and throw an exception.
Recently I had an interview to save the huge count of employee details in DS.
I gave the solution as Hashmap with emp Id as key.
The follow up question was if the user wants to search based on name how to implement it. I suggested to use emp name as key and save all the employees with same name as Arraylist.
The next follow up question was tricky, need to create ONE map where user can search based on emp Id or emp name. How to implement this in map?
Implement it in memory efficient way.
This is a dirty solution (yes--very dirty, never do it on production!), but it will work if keys are of different types and one is not subtype of another (e.g. long and String). Put every employee by both keys, and get by provided key, either id or name:
Map<?, List<Employee>> map = new HashMap<>();
public void putEmployee(Employee e) {
map.put(e.id, Arrays.asList(e)); // put by id
if (!map.containsKey(e.name)) {
map.put(e.name, new ArrayList<>());
}
map.get(e.name).add(e); // put by name
}
public Employee getById(long id) {
return map.containsKey(id) ? map.get(id).get(0) : null;
}
public List<Employee> getByName(String name) {
return map.containsKey(name) ? map.get(name) : Collections.emptyList();
}
In production code, I'd use two separate maps or custom dictionary class.
I have come up with a solution. Please post your suggestions.
Step 1: Form the hashmap with emp id as key and emp object as value.
Step 2: For the same name create a list of emp id who matches the name Ex: name = 'XYZ' id={101,102,103,...}
Step 3: Insert this name as key and arraylist as value to the same map
Here we are not storing complete employee detail twice. Just trying to maintain a relationship between name and id. So comparatively it could be memory efficient.
This is a pretty easy question to answer: Just convert the IDs to Strings and store employees twice - once under the name and again under the id-as-string.
Your idea of using a List as the value is fine - for IDs, the list would be of size 1.
Note that it would be better to use two maps, because you only ever have one employee per ID and you wouldn't have to deal with a list of size 1 as a degenerate case, so:
Map<Integer, Employee> employeesById;
Map<String, Set<Employee>> employeesByName;
Especially note that you wouldn't use less memory by using just one map. In fact, you would use more memory than storing employees in separate maps for ID keys and name keys.
One way to do this would be to create a Key object that can be searched by either the name or the id:
public enum KeyType {
ID, NAME;
}
public class SearchKey {
private KeyType keyType;
private String value;
// constructor and getters snipped for brevity's sake
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
SearchKey searchKey = (SearchKey) o;
return keyType == searchKey.keyType && value.equals(searchKey.value);
}
#Override
public int hashCode() {
int result = keyType.hashCode();
result = 31 * result + value.hashCode();
return result;
}
public class Directory {
private Map<SearchKey, Set<Employee>> directory = new HashMap<>();
public void addEmployee(Employee e) {
// Add search by id
directory.put
(new SearchKey(KeyType.ID, e.getId()), Collections.singleton(e));
// Add search by name
SearchKey searchByName = new SearchKey(KeyType.NAME, e.getName());
Set<Employee> employees = directory.get(searchByName);
if (employees == null) {
employees = new HashSet<>();
directory.put(searchByName, employees);
}
employees.add(e);
}
public Employee getById (String id) {
// Assume that the ID is unique
return directory.get(new SearchKey(KeyType.ID, id)).iterator().next();
}
public Set<Employee> getByName (String name) {
return directory.get(new SearchKey(KeyType.NAME, name));
}
}
I have a hashmap for orders and another one for orderitems. A method which puts the data into the hashmaps is executed like this:
// THIS ONE ADDS THE ORDERS
// (int orderNumber, String Datum, String salesperson, int customernumber)
mainController.addBestallning(500, "2012/01/01", "Hendrik Gustafsson", 1001);
// THIS ONE ADDS THE ORDERED ITEMS
// (int orderNumber, int linePos, Artikel product, int amount, double price)
mainController.addBestallningsOrderRad(500, 1, mainController.getAllaArtiklar().get(101), 5, 100.00);
Once I find an order by its ordernumber, how do I find the ordereditems?
The only link I have now is the ordernumber, which I save in orderitemshashmap, so I assume some sort of iteration needs to take place, find the matches and return the results.
I tried doing this and got it to work, but only under condition that all of the orderitem positions are also unique.
So, if I was to add another order like this:
mainController.addBestallning(501, "2011/05/02", "Sven Karmageddon", 1002);
mainController.addBestallningsOrderRad(501, 1, mainController.getAllaArtiklar().get(101), 5, 100.00);
I could not find the orderitems for order 501.
Here is what I tried so far. Made a method to find all orders of a customer:
public HashMap<Integer, Bestallning> getAllaKundOrdrar() {
HashMap<Integer, Bestallning> allaKundOrderHashMap = new HashMap<>();
//iterate through all orders
//find the ones which belong to customerid
//place them in allaKundOrderHashMap
//return allaKundOrderHashMap
Iterator iter = tmpBestallningsregister.getAllaBestallningar().keySet().iterator();
while (iter.hasNext()) {
Integer key = (Integer) iter.next();
//String value = (String) controller.getAllaKunder().get(key).getKundNamn();
if ((customerNrToFindOrdersFor) == getAllaBestallningar().get(key).getKundNr()) {
//found an order for this customer, putting it in the hashmap
allaKundOrderHashMap.put(key, getAllaBestallningar().get(key));
}
}
return allaKundOrderHashMap;
}
A method to find all ordereditems from all customers (100% wrong to search like this, I know) and get the ones beloning to a specific order:
//RETURN OF ORDERRADERS HASHMAP FOR SPECIFIC ORDER VIA ORDERREGISTER
public HashMap<Integer, BestallningsOrderRad> getAllaBestallningsBestallningsOrderRader() {
HashMap<Integer, BestallningsOrderRad> allaBestallningsOrderRaderHashMap = new HashMap<>();
//iterate through all orderrader
//find the ones which belong to orderid
//place them in allaKundOrderRaderHashMap
//return allaKundOrderRaderHashMap
Iterator iter = tmpBestallningsregister.getAllaBestallningsOrderRader().keySet().iterator();
while (iter.hasNext()) {
Integer key = (Integer) iter.next();
if ((orderNrToFindOrderRaderFor) == tmpBestallningsregister.getAllaBestallningsOrderRader().get(key).getBestallningsNr()) {
//found an orderrad for this order, putting it in the hashmap
//allaBestallningsOrderRaderHashMap.put(key, getAllaBestallningsOrderRader().get(key));
allaBestallningsOrderRaderHashMap.put(key, getAllaBestallningsOrderRader().get(key));
}
}
return allaBestallningsOrderRaderHashMap;
}
Anyone care to tell me what is it that I am doing wrong?
I've been at this for 20 hours straight...
Don't use two different Map, but only one. What you need is to properly define a Order class that holds all the order data (including suborders, which are sheldom used outside the order) and use just a Map<Integer,Order>
If you insist in having two separate Maps, the second uses the same id but stores a List (it looks like you want it ordered) of suborders.
private Map<Integer, Order> orders;
private Map<Integer, List<SubOrder> suborders;
Stopping a moment before beginning to code and thinking the more appropiate data structures will usually save you a lot of "hell" later.
I have a task to play with Java Collections framework. I need to obtain a users list from a database, and store it in a collection. (This is finished and users are stored in a HashSet). Each user is an instance of Person class described with name, surname, birth date, join date, and some other parameters which are not important now. Next I need to store the list in different collections (there's nowhere stated how many) providing functionality to sort them by:
- name only
- name, surname, birthdate
- join date
Ok, so to start with, my Person stores data as Strings only (should I change dates to Date ?). I've started implementing sorting with "by name, surname, birthdate", cause that's what I get after calling sort on list with Strings. Am I right ?
public List createListByName(Set set){
List ret = new ArrayList<String>();
String data = "";
for(Object p: set){
data = p + "\n";
ret.add(data);
}
Collections.sort(ret);
return ret;
}
But what with the rest ? Here's my Person :
class Person {
private String firstname;
private String lastname;
)..)
Person(String name, String surname, (..)){
firstname = name;
lastname = surname;
(..)
}
#Override
public String toString(){
return firstname + " " + lastname + " " + (..);
}
}
I wouldn't convert everything to strings to start with. I would implement Comparator<Person> and then sort a List<Person>:
public List<Person> createListByName(Set<Person> set){
List<Person> ret = new ArrayList<Person>(set);
Collections.sort(ret, new NameSurnameBirthComparator());
return ret;
}
The NameSurnameBirthComparator would implement Comparator<Person> and compare two people by first comparing their first names, then their surnames (if their first names are equal) then their birth dates (if their surnames are equal).
Something like this:
public int compare(Person p1, Person p2) {
// TODO: Consider null checks, and what to do :)
int firstNameResult = p1.getFirstName().compareTo(p2.getFirstName());
if (firstNameResult != 0) {
return firstNameResult;
}
int surnameResult = p1.getSurname().compareTo(p2.getSurname());
if (surnameResult != 0) {
return surnameResult;
}
return p1.getBirthDate().compareTo(p2.getBirthDate());
}
And yes, I would store the date of birth as a Date - or preferably as a LocalDate from JodaTime, as that's a much nicer library for date and time manipulation :)
so I should write multiple comprators on Person for each task ?
Given this is a homework task, then I would say that is the way you would start to learn about Comparators.
For interest sake only you can do this by creating a couple of resuable Comparators.
You can use the Bean Comparator to sort on individual properties.
Then you can use the Group Comparator to sort on multiple properties.