How to write my own comparator class in java? - java

I didn't find proper solution for the below scenario. I have employee names and location. In each location many employees can work.
Example: assume that employee names are unique so I consider it as a key and value as location.
TreeMap<String,String> t=new TreeMap<String,String>();
t.put(mike, Houston);
t.put(arian, Houston);
t.put(John, Atlanta);
Well my scenario is i have to write my own comparator where location is sorted first and when there are multiple locations of same name then they need to be sorted by employees. Any kind of help is appreciated.

you need a structure, and compareTo:
public class EmpLoc implements Comparable<EmpLoc> {
String employee;
String location;
public EmpLoc (String _employee, String _location)
{
employee=_employee;
location=_location;
}
#Override
public int compareTo(EmpLoc other)
{
int last = this.location.compareTo(other.location);
return last == 0 ? this.employee.compareTo(other.employee) : last;
}
}

The problem is in your data structure. TreeMap ensure your keys are always sorted in an order, but your key doesn't have full information you need to sort. Instead what you need is probably
TreeSet<Employee> employees = new TreeSet<>(employeeComparator);
where Employee is:
public class Employee {
private String name;
private String location;
/* getters & setters omitted */
}
Now you can create a comparator for Employee

You can use similar structure:
Map<String, List<String>> map = new TreeMap<>(<your_own_comparator_for_locations_or_default_one>);
This is Multimap, and this is implementation by conventional means, but also there are third-party implementation, e.g. Guava. Guava has some sorted, synchronized and immutable implementations of multimaps, you can use them by default or to see how to do some things.
You can put values like below:
public void putEmployees(String location, String employee) {
List<String> employees = map.get(location);
if (employee == null) {
employees = new ArrayList<>();
}
employees.add(employee);
Collections.sort(employees, <your_own_comparator_for_employees_or_default_one>);
map.put(location, employees);
}

Related

Use of Predicate in comparing two list of different type in Java

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");
}

Multi Key Hashmap

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));
}
}

Returning all the keys from a HashMap withou looping

I am attemping to populate a JComboBox with the names of cities.
My program has a class called 'Country'. The Country object contains a HashMap of objects called 'City' with a method getName, returning a String value.
public class Country {
private final Map<String, City> cities = new HashMap<>();
public Collection<City> getCities() {
return cities.values();
}
}
public class City {
String cityName;
public String getName() {
return cityName;
}
}
Is it possible to return an String array of cityName without using a loop? I was trying the following but it did not work:
Country country 1 = new Country();
String[] cityNames = country1.getCities().toArray();
JComboBox cityChoice = new JComboBox(cityNames);
This returns an Array of City objects, however I am not sure how to use the City getName method in conjunction with this.
You can not avoid looping. Either, you will loop, or Java will loop in the background.
You can avoid writing your own loop if keys in your map are city names. Then, you could only ask .keySet() from the map. But, even in that case, Java would loop in the background and copy the keys.
Other way is that you loop, but hide the loop in some method (lets say getCitiesArray()) in the class. So, you could do country1.getCitiesArray(); in the calling method. Code would look better and be easier to read, but you would still need to have loop inside of the class.
You can store Map key as CityName then do below to get Names.
cities.keySet();
The city object can be used directly in the combobox with some minor alterations.
public class City {
String cityName;
public String getName() {
return cityName;
}
#Override
public String toString() {
return getName();
}
}
Then the population code
Country country1 = new Country();
City[] cities = country1.getCities().toArray();
JComboBox<City> cityChoice = new JComboBox<City>(cities);
You should probably override hashCode and equals also.
If you are using Java 8, you can use the Stream API to map the names of the cities to a String:
String []cityNames = country1.getCities().stream().map(City::getName).toArray(String[]::new);

Find most common Object from a list

Let's say I have a List of Employee Objects. The Employee Objects have a getDepartment method which returns a Department Object. I want to iterate through that list to find the department with the most Employees (i.e. the Department Object returned most often from getDepartment). What is the fastest way to do this?
public class Employee{
static allEmployees = new ArrayList<Employee>();
int id;
Department department;
public Employee(int id, Department department){
this.id = id;
this.department = department;
allEmployees.add(this);
}
public Department getDepartment(){
return department;
}
public static List<Employee> getAllEmployees(){
return allEmployees;
}
}
public class Department{
int id;
String name;
public Department(int id){
this.id = id;
}
public String getName(){
return name;
}
}
If there's two departments with an equal number of employees it doesn't matter which is returned.
Thanks!
create a map of department id -> counts.
that way you get a collection of all the counts by id. You can also maintain a max item that is a reference to the map entry with the highest count.
the algorithm would be something like:
1) Initialize a Map and a currentMax
2) loop through employees
3) for each employee, get its department id
4) do something like map.get(currentId)
a) if the current count is null, initialize it
5) increment the count
6) if the incremented count is > currentMax, update currentMax
This algorithm will run in O(n); I don't think you can get any better than that. Its space complexity is also O(n) because the number of counts is proportional to the size of the input.
If you wanted, you could create a class that uses composition (i.e. contains a Map and a List) and also manages keeping pointers to the Entry with the highest count. That way this part of your functionality is properly encapsulated. The stronger benefit of this approach is it allows you to maintain the count as you enter items into the list (you would proxy the methods that add employees to the list so they update the map counter). Might be overkill though.
Here's a vanilla Java 8 solution:
Employee.getAllEmployees()
.stream()
.collect(Collectors.groupingBy(Employee::getDepartment, Collectors.counting()))
.entrySet()
.stream()
.max(Comparator.comparing(Entry::getValue))
.ifPresent(System.out::println);
It passes through the list of employees at most twice. An equivalent solution using jOOλ, if you're willing to add a third-party dependency, is this:
Seq.seq(Employee.getAllEmployees())
.grouped(Employee::getDepartment, Agg.count())
.maxBy(Tuple2::v2)
.ifPresent(System.out::println);
(Disclaimer: I work for the company behind jOOλ)
I would do something like this using Guava:
Multiset<Department> departments = HashMultiset.create();
for (Employee employee : employees) {
departments.add(employee.getDepartment());
}
Multiset.Entry<Department> max = null;
for (Multiset.Entry<Department> department : departments.entrySet()) {
if (max == null || department.getCount() > max.getCount()) {
max = department;
}
}
You would need a correct implementation of equals and hashCode on Department for this to work.
There's also an issue here that mentions the possibility of creating a "leaderboard" type Multiset in the future that would maintain an order based on the count of each entry it contains.
Since you just want to count employees, it's relatively easy to make a map.
HashMap<Department, Integer> departmentCounter;
that maps Departments to the number of employees (you increment the count for every employee). Alternatively, you can store the whole Employee in the map with a list:
HashMap<Department, List<Employee>> departmentCounter;
and look at the size of your lists instead.
Then you can look at the HashMap documentation if you don't know how to use the class:
http://download.oracle.com/javase/1.4.2/docs/api/java/util/HashMap.html
Hint: you will need to use HashMap.keySet() to see which departments have been entered.
I would do it like that, modulo == null and isEmpty checks:
public static <C> Multimap<Integer, C> getFrequencyMultimap(final Collection<C> collection,
final Ordering<Integer> ordering) {
#SuppressWarnings("unchecked")
Multimap<Integer, C> result = TreeMultimap.create(ordering, (Comparator<C>) Ordering.natural());
for (C element : collection) {
result.put(Collections.frequency(collection, element), element);
}
return result;
}
public static <C> Collection<C> getMostFrequentElements(final Collection<C> collection) {
Ordering<Integer> reverseIntegerOrdering = Ordering.natural().reverse();
Multimap<Integer, C> frequencyMap = getFrequencyMultimap(collection, reverseIntegerOrdering);
return frequencyMap.get(Iterables.getFirst(frequencyMap.keySet(), null));
}
There is also CollectionUtils.getCardinalityMap() which will do the job of the first method, but this is more flexible and more guavish.
Just keep in mind that the C class should be well implemented, that is have equals(), hashCode() and implement Comparable.
This is how you can use it:
Collection<Dummy> result = LambdaUtils.getMostFrequentElements(list);
As a bonus, you can also get the less frequent element with a similar method, just, feed the first method with Ordering.natural() and do not reverse it.

java get sub list from a list of objects

there is a dependent list
Dependents contains
String emp_Id, name etc,
List<Dependent> dependentList;
dependentList contains all the dependent information of an employee.
how to get the list of dependents by providing the emp_Id ?
for example an employee will have 2 or 3 dependents.
ok i dont want to loop over it.
i tried binary search on list using comparator but it does not return the desired data.
already i will loop over the employee list... subsequently i should get the depends of the particular employee...
what will be the best & efficient solution ?
Binary search works only if the list is sorted according to the comparator. For lists that are not sorted or sorted according to other criteria, you have to filter them.
Either loop though the list and do whatever you want to do in the loop body
Or use a filter functionality from a library
If you want to filter, then I recommend Google Collections (or Google Guava, which is a superset of Google collections):
Collection<Dependent> filtered = Collections2.filter(dependentList, new Predicate<Dependent>() {
public boolean apply(Dependent from) {
return from != null && from.getId().equals(id_so_search_for);
}
}
Of course, you are not restricted to .equals(), but can match according to any operation required (e.g. by regular expression).
If searches for one kind of data heavily outweight searches for any other kind of data, then storing them in a Map<kind-of-id, Dependent> may be a good choice as well. You still can retrieve a collection of all stored objects using Map.values().
If one key maps to several items, then either use a Map<kind-of-id, Collection<Dependent>> or (better) consider using existing Multimap functionality: com.google.common.collect.Multimap or org.apache.commons.collections.MultiMap (note that Apache Commons does not have a genericized version of this).
You want to model relationships. I guess, you have the basic dependencies:
Supervisor is-a Employee
Supervisor has-many Employees (Dependants in your case)
So a very basic implementatin could go like this:
public class Employee {
int emp_id;
// more fields, more methods
}
public class Supervisor extends Employee {
private List<Employee> dependants = new ArrayList<Employee>();
// more fields, more methods
public List<Employee> getDependants() {
return dependants;
}
}
public class StaffDirectory {
private Map<Integer, Employee> staff = new HashMap<Integer, Employee>();
public static List<Employee> getAllDependantsOf(int employeeId) {
Employee employee = staff.get(employeeId);
if (employee instanceof Supervisor) {
return ((Supervisor) employee).getDependants());
} else {
return Collections.emptyList();
}
}
}
What have you tried so far? Do you have anything written?
Here is a general guess:
int employeeToFind = 10;//the id to search for
for(Dependant dep : dependentList ) {
if(dep.getEmployeeId() == employeeToFind) {
//do something
}
}
You could also store dependents in a Hashtable<Integer employeeId,List<Dependent>>(); keyed by EmployeeId for an easy lookup.
As alzoid mentioned, a HashMap or HashTable is the perfect data structure for this task. If you have any chance to load your instances of Dependent into such an object, do so.
Still, have this delicious code:
String emp_Id //IDs are usually integer, but I'll go with your example
List<Dependent> dependentList; //assume this is populated
List<Dependent> desiredSublist = new ArrayList<Dependent>();
for(Dependent dep:dependentList){
//make sure to compare with equals in case of Id being String or Integer
if(dep.getId().equals(emp_Id)){
desiredSubList.add(dep);
}
}
//desiredSublist now contains all instances of Dependent that belong to emp_Id.

Categories