Collection sort of list contains 2 objects - java

I have a list, which contains 2 objects of type Departments and Managers.
I need to sort the list alphabetically by Departments. The Department class implements Comparable<Department> and has the method compareTo. But I receive an error message:
"The method sort(List, Comparator) in the type
Collections is not applicable for the arguments (List, new
Comparator(){})"
public static List<?> getLst(String fileName)throws FileNotFoundException, IOException,ClassNotFoundException {
List<Object> lst = new LinkedList<>();
BufferedInputStream f;
try(ObjectInputStream i = new ObjectInputStream(f=new BufferedInputStream(new FileInputStream(fileName)))){
while (f.available()>0) {
lst.add(i.readObject());
}
Collections.sort(lst, new Comparator<Department>() {
#Override
public int compare(Department object1,Department object2) {
return object1.getDepName().compareTo(object2.getDepName());
}
});
}
return lst;
}

You are not using generics correctly.
Collections.sort() wants:
a List<T> and
a matching Comparator<T>
You are providing a List of Objects; but a Comparator of Departments. That simply can't work.
So, one way of resolving this - first change your list to use the proper generic type:
List<Department> departments = new ArrayList<>();
and later ... add the (now necessary) cast so that the incoming "Object" can be added to that list of departments - if it has the correct type!
Object fromStream = i.readObject();
if (fromStream instanceof Department) {
departments.add( (Department) fromStream);
} else {
// consider what to do with managers objects ...
( please note: lst is a bad name; it says nothing, and that one saved character only adds confusion. Use names that express what the thing behind is about; like departments to make clear: something that contains, well departments in plural )
Update: the generics give a hint that you have a design problem here. If you want to sort departments, then your list containing departments should not contain anything else.
In other words: the real answer here is to not use one list that contains different types of objects, but to use two lists instead.

The design that puts managers an departments in the same list sounds suspect. Are you making a model for a Tree widget? There are better ways for that ...
In any case, you can do one of two things:
provide Comaparator and cast inside as needed (bad idea)
or have both Department and Manager implement HasDepartment with getDepartment() method, and build your Comparator for that.

Related

Separate a list of items into new, present and present-and-needs-stuff-done-to-it

I have a list of items which I want in my database. Some of the items are new and have to be saved, others are already in the database, but have to be updated and some of those that need an update might be eligible for a special treatment.
Now I just run through them and put them in other lists according to their properties and then hand the lists to the respective database (or special) methods that deal with it.
I just don't think it's pretty, it does a bit much and it has nested ifs.
But can't really come up with a nicer way of doing this.
Here is the (slightly simplified) code
List<Item> newItemList = new ArrayList<>();
List<Item> existingItemList = new ArrayList<>();
List<Item> specialItemList = new ArrayList<>();
for(Item item : items)
{
if(item.isNew())
{
newItemList.add(item);
}
else
{
if(item.isSpecial())
{
specialItemList.add(item);
}
existingItemList.add(item);
}
}
itemHandler.saveItems(newItemList);
itemHandler.updateItems(existingItemList);
specialManager.specialStuff(specialItemList);
Your current code does exactly what is required. Your requirement calls for three different lists, and you iterate items once to create them. It is the most efficient approach. You could write the code in three lines - see below - (the helper method is for clarity) - but then you iterate items three times (but don't require 3 lists). I believe any attempt to make 'nicer' code loses some optimization.
itemHandler.saveItems(createList(items, i -> i.isNew()));
specialManager.specialStuff(createList(items, i -> !i.isNew() && i.isSpecial()));
itemHandler.updateItems(createList(items, i -> !i.isNew()));
Helper method:
public List<Item> createList(List<Item> allItems, Predicate<Item> p) {
return allItems.stream().filter(p).collect(Collectors.toList());
}
With Java 8, you could simplify by grouping the Lists by State (new or existing).
An enum could represent the state : enum State {NEW, EXISTING} and the Item class should declare a State getState() method.
Map<ItemState, List<Item>> itemListByState =
items.stream()
.collect(Collectors.groupingBy(Item::getState));
itemHandler.saveItems(itemsByState.get(State.NEW));
itemHandler.updateItems(itemsByState.get(State.EXISTING));
specialManager.specialStuff(itemsByState.get(State.EXISTING).stream()
.filter(Item::isSpecial)
.collect(Collectors.toList()));
You could of course introduce intermediary variables for the Lists but I don't think that it is really required and it reduces potential side effects between them.
Try creating another method like:
boolean add(List<Item> items, Item item, boolean doAdd) {
if (doAdd) {
items.add(item);
}
}
And call it like:
add (newItemList, item, item.isNew());
add (specialItemList, item, item.isSpecial() & !item.isNew());
add (existingItemList, item, !item.isNew());

How do I add to a set based on a specific predicate in Java?

I have a set in Java containing people:
Set<Person> uniquePeople = new HashSet<Person>();
I also have a list of a ton of people (of whom some possess the same name, eg. there is more than one "Bob" in the world).
List<Person> theWorld = // ... a BIG list of people
I want to iterate through this list and add a person to the uniquePeople set if and only if their name doesn't exist in the set, eg:
for (Person person : theWorld) {
uniquePeople.add(person IFF uniquePeople.doesNotContain(person.name));
}
Is there an easy way to do this in Java? Also, Guava might do this (?) but I haven't used it at all so I would appreciate a point in the right direction.
A better option would be to abandon using a Set and instead use a Map<String, Person> (keyed off of the name).
If you want to use a set, I suggest you use a new object type (that will just contain a name and maybe a reference to a Person).
Make sure you override equals so that it will only compare the names and then you can get a set of all unique people.
You could also subclass person to override the equals to do what you want.
Sets by definition will not do what you want with just a person since they depend entirely on using equals so these are your workaround options. You could also implement (or find online) a set that takes a comparator to use instead of relying on equals but I don't think such a class exists in standard java.
Use Guava's Equivalence to wrap your objects if you don't want to (or can't) override equals and hashCode:
Set<Equivalence.Wrapper<Person>> set = Sets.newHashSet();
Equivalence<Person> personEquivalence = Equivalence.onResultOf(
new Function<Person, String>() {
#Override public String apply(Person p) {
return p.name;
}
});
set.add(personEquivalence.wrap(new Person("Joe", "Doe")));
set.add(personEquivalence.wrap(new Person("Joe", "Doe")));
set.add(personEquivalence.wrap(new Person("Jane", "Doe")));
System.out.println(set);
// [PersonEquivalence#8813f2.wrap(Person{firstName=Jane, lastName=Doe}),
// PersonEquivalence#8813f2.wrap(Person{firstName=Joe, lastName=Doe})]
#DanielWilliams has a good idea too, but using Equivalence.Wrapper is more self-documenting - after all you don't want to create new object other than wrapper.
I am not sure why people got downvoted here.
You absolutely want a Set. Not only do your requirements meet the definition and functionality of 'Set' but Set implementations are designed to quickly identify duplicates either via hash or Comparative identity.
Let's say you had a List implementation that took a deligate and a predicate:
List uniquePeople = new PredicatedList(new ArrayList(),UnqiuePersonPredicate.getInstance())
public class PredicatedList<T> implements List<T> {
private List<T> delegate = null;
private Predicate<T> predicate;
public PredicatedList<List<T> delegate, Predicate p) {
this.delegate = delegate;
this.predicate = p;
}
// implement list methods here and apply 'p' before calling your insertion functions
public boolean add(Person p) {
if(predicate.apply(p))
delegate.add(p);
}
}
For this to work you would need to have a predicate that iterates over the list to find an equal element. This is an O(N) operation. If you use HashSet then it's O(1) < n < O(N). Your amortized identity check is the load factor * N. And, usually much closer to O(1)
If you use TreeSet you will get O(log(n)) because the elements are sorted by identity and you need only log(n) time to binary search.
Define hashCode()/equals based on 'name' or whatever you want and use HashSet or use TreeSet and define Comparable/Comparator
If your return type MUST be a List then do:
Set uniquePeople = new HashSet();
uniquePeople.add(...);
List people = new LinkedList(uniquePeople);
You could do it with guava, the only thing is that Person is going to need an equals/hashcode method.
ImmutableSet<String> smallList = ImmutableSet.of("Eugene","Bob");
ImmutableSet<String> bigList = ImmutableSet.of("Eugene","Bob","Alex","Bob","Alex");
System.out.println(Iterables.concat(smallList, Sets.difference(bigList, smallList)));
//output is going to be : [Eugene, Bob, Alex]

Guava: get a list of variables from a list of objects containing the variable

The idea:
I have an object
public class Book(){
private String name;
private Integer nbOfPage;
public Book()
...
}
And I got a list of this Object
List<Book> books = new ArrayList<Book>();
Now I was wondering if in guava or another librairie, there was a quick way to get a list of all the different names from all the books I got, something I could do:
List<String> names = new ArrayList<String>();
for (Book aBook : books){
if (!names.contains(aBook.getName()){
names.add(aBook.getName());
}
}
I think this way is a bit "heavy", my book list can have from 200 to 1200 books.
Regards,
Use Guava's Multimaps.index. It does exactly what you'd expect it does.
List<Book> books = ...
Function<Book,String> bookToName = new Function<Book,String>() {
String apply(Book b) { return b.getName(); }
}
Multimap<String,Book> booksByName = Multimaps.index(books, bookToName);
Then, play around with your Multimap, like booksByName.keys() if you need only the names.
Use a Set (such as HashSet) for the book names collection, this way you don't have to check every time whether you already have the current book name. You can insert elements in constant time into a HashSet, and you will have no duplicates. Make sure you have a good hashCode() method and a corresponding equals, see this: What issues should be considered when overriding equals and hashCode in Java?
A faster solution does not exist, because you have to iterate over all the books at least once.

Creating instance list of different objects

I'm tring to create an arraylist of different class instances. How can I create a list without defining a class type? (<Employee>)
List<Employee> employees = new ArrayList<Employee>();
employees.add(new Employee());
Employee employee = employees.get(0);
You could create a list of Object like List<Object> list = new ArrayList<Object>(). As all classes implementation extends implicit or explicit from java.lang.Object class, this list can hold any object, including instances of Employee, Integer, String etc.
When you retrieve an element from this list, you will be retrieving an Object and no longer an Employee, meaning you need to perform a explicit cast in this case as follows:
List<Object> list = new ArrayList<Object>();
list.add("String");
list.add(Integer.valueOf(1));
list.add(new Employee());
Object retrievedObject = list.get(2);
Employee employee = (Employee)list.get(2); // explicit cast
List<Object> objects = new ArrayList<Object>();
objects list will accept any of the Object
You could design like as follows
public class BaseEmployee{/* stuffs */}
public class RegularEmployee extends BaseEmployee{/* stuffs */}
public class Contractors extends BaseEmployee{/* stuffs */}
and in list
List<? extends BaseEmployee> employeeList = new ArrayList<? extends BaseEmployee>();
List anyObject = new ArrayList();
or
List<Object> anyObject = new ArrayList<Object>();
now anyObject can hold objects of any type.
use instanceof to know what kind of object it is.
I believe your best shot is to declare the list as a list of objects:
List<Object> anything = new ArrayList<Object>();
Then you can put whatever you want in it, like:
anything.add(new Employee(..))
Evidently, you will not be able to read anything out of the list without a proper casting:
Employee mike = (Employee) anything.get(0);
I would discourage the use of raw types like:
List anything = new ArrayList()
Since the whole purpose of generics is precisely to avoid them, in the future Java may no longer suport raw types, the raw types are considered legacy and once you use a raw type you are not allowed to use generics at all in a given reference. For instance, take a look a this another question: Combining Raw Types and Generic Methods
How can I create a list without defining a class type? (<Employee>)
If I'm reading this correctly, you just want to avoid having to specify the type, correct?
In Java 7, you can do
List<Employee> list = new ArrayList<>();
but any of the other alternatives being discussed are just going to sacrifice type safety.
If you can't be more specific than Object with your instances, then use:
List<Object> employees = new ArrayList<Object>();
Otherwise be as specific as you can:
List<? extends SpecificType> employees = new ArrayList<? extends SpecificType>();
I see that all of the answers suggest using a list filled with Object classes and then explicitly casting the desired class, and I personally don't like that kind of approach.
What works better for me is to create an interface which contains methods for retrieving or storing data from/to certain classes I want to put in a list. Have those classes implement that new interface, add the methods from the interface into them and then you can fill the list with interface objects - List<NewInterface> newInterfaceList = new ArrayList<>() thus being able to extract the desired data from the objects in a list without having the need to explicitly cast anything.
You can also put a comparator in the interface if you need to sort the list.
I know this is an old question, but there's a nice and easy way to do this (it works with the mostly recent versions of ElasticSearch Rest API).
The search object goes like:
SearchResponse<JsonData> search = client.search(s -> s
.index(index)
.query(query),
JsonData.class);
And then I iterate over the response like this:
for (Hit<JsonData> hit: search.hits().hits()) {
String stringSource = hit.source().toString();
MySavedRegister mySavedRegister = mapper.readValue(stringSource, mySavedRegister .class);
mylist.add(esGenericEvent);
}
Where mySavedRegister stands for the class that has the hits' sources parameters.

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