How to loop through an ArrayList within a custom Object? - java

I realize that variations of this question have been asked before, but I am having a uniquely difficult time figuring out how to complete the following task:
I have an object that looks something like this (please note, "Skill" and "Certification" are ENUMS):
Public Employee {
String name;
List<Skill> employableSkills = new ArrayList<>();
List<Certification> certifications = new ArrayList<>();
...
}
In another class, I've got a
List<Employee> listOfEmployees;
and I'm trying to loop through it like this:
// determine the total number of employees who know Java
int numberOfEmployeesWhoKnowJava = 0;
for (Employee employee : listOfEmployees) {
if (employee.employableSkills.contains( ?? )) {
numberOfEmployeesWhoKnowJava++;
}
I'm struggling to get the exact syntax on the if-statement. I have tried this:
if(employee.employableSkills.contains(Employee.EmployableSkills.JAVA)) {
but EmployableSkills in this string gets "cannot resolve symbol."
How should I loop through the List on each Employee object and check if it contains JAVA?
Edit: It turns out I was making a fundamental error. In OOP, it is best not to expose the data from one class to another class. Instead, I wrote getters in the Employee class, then called those getters from my other class. That way, the data in Employee is not directly exposed to the class that needed it.

Even if you get syntax right, the following code will have a bad complexity of order n - O(n).
if(employee.employableSkills.contains(Employee.EmployableSkills.JAVA)) {
Change you List to hash implementation of set
Set<Skill> employableSkills = new HashSet<>();
and now loop through the employees
int numberOfEmployeesWhoKnowJava = 0;
for (Employee employee : listOfEmployees) {
if (employee.employableSkills.contains(Skill.JAVA)) {
numberOfEmployeesWhoKnowJava++;
}
}
This will give a complexity of O(1) while looking skills

Your question is a little unclear, but if my interpretation is correct, try this:
if (employee.employableSkills.contains(Skill.JAVA))

Related

How do you adapt sequential search to return mutiple results?

new to the site, apologies for any mistakes below.
EDIT: Added the code to a Pastebin. Code has been obscured slightly for my benefit from and employee to customer basis. Apologies if search and replace failed to pick up an instance of employee or emp remaining, can't see one myself.
Am struggling with what I assume is a relatively easy problem. I am trying to adapt a sequential search to return matching first names. Multiple instances of the same first name exist and must be accounted for. I have the template below to work from and have gotten several examples in the past to work without much issue but am having a brain fart when it comes to adapting it for multiple results. Am even unsure of whether to return a series of ints or Strings.
static int SequentialSearch(int arr[], int searchKey){
int n = arr.length;
for (int i = 0; i < n; i++){
if (arr[i] == searchKey)
return i;
}
return -1;
}
Can I still return -1 if something is not found while returning the relevant indices in a temporary array or is it a better method to return a string and concatanate the answers. Will the return i; close the loops as soon as the first instance is found or will it complete the for loop?
Have been moving from doing well to struggling within the last month and this question has compounded all of my issues. I am not bound to the template in anyway so if a different one exists for multiple returns I'd be much obliged.
UPDATE: With the code linked above I am getting a response but they're all null
EDIT: In response to a question request below from #MrSmith42 , the expected output would be a return of employee details for any employee with a matching first name. The toString has already been done and now is linked at the start here and it works for a different output (a sorting algorithm) so I would hope to be able to repeat the same steps once the method is correct to get the right output rather painlessly (could be a hope in vain)
You could return a List<Customer> with the results or a null if there are none. Or just return the list and use the size to determine if there were any results.
static List<Customer> SequentialSearch(Customer arr[], String firstName) {
List<Customer> results = new ArrayList<>();
for (Customer customer : arr) {
if (customer.getFirstName().equalsIgnoreCase(firstName)) {
results.add(customer);
}
}
return results.size() > 0 ? results : null;
}
If you're interested, you could also return an array of customers using streams like so.
Customer[] results = Arrays.stream(customers).filter(
c -> c.getFirstName().equalsIgnoreCase(firstName))
.toArray(Customer[]::new);
// or a list
List<Customer> results = Arrays.stream(customers).filter(
c -> c.getFirstName().equalsIgnoreCase(firstName))
.collect(Collectors.toList());

What is the best way to search elements in a list with nested elements?

I have 2 classes:
public class ChatGroup{
final public String name;
private List<ChatContact> contacts;
/* ---getters/setters/constructors-- */
}
public class ChatContact implements Parcelable, Comparable {
final public String name;
final public String jid;
public Status status;
/* ---getters/setters/constructors-- */
}
Then I have a list of ChatGroup items:
List<ChatGroup> chatGroupList = .....;
As you can see every ChatGroup has a list of ChatContact., and what I need is to search inside chatGroupsList, for ChatContacts that matches a query (search by username).
A way I'm doing, is do an auxilar list, search for every group, and look "inside" for ever chatContact, if exist I add the group with the contact:
private List<ChatGroup> searchContacts(String query) {
List<ChatGroup> filteredContacts = new ArrayList<>();
for (ChatGroup chatGroup : chatGroupList) {
ChatGroup auxChatGroup = new ChatGroup(chatGroup.name);
for (ChatContact chatContact : chatGroup.getContacts()) {
if (chatContact.name.toLowerCase().contains(query)) {
auxChatGroup.addContact(chatContact);
}
}
if (auxChatGroup.getContacts().size() > 0)
filteredContacts.add(auxChatGroup);
}
for (ChatGroup chatGroup : filteredContacts) {
Collections.sort(chatGroup.getContacts());
}
return filteredContacts;
}
All of this works perfect. But right now, this list has few groups with few contacts each one, but in a future will be a high number of elements, and this could be a "slow" solution.
So my question is, there is another faster way to do this type of search?
Unfortunately, if you are seriously going to search for something like "a" and want everyone who has the letter A at any point in their name, that type of search does not index well.
But looking at your algorithm, I see a few possible improvements.
Initialize ChatGroup auxChatGroup = null and only create the object when you find a result that matches the filter. This will avoid creating a few unnecessary objects if you have lots of rooms.
Sorting the list of contacts every time you do a search seems like a lot of wasted effort. Using a sorted collection such as TreeSet could offer you a huge time savings on each search.
If the number of groups becomes huge, as in millions, then consider using a multi-threaded search.
Depending on your use case, it may be possible to return a filtered "view" instead of a snapshot. However that may add some complexity and possible gotchas.

Returning an arraylist and iterating throught the returned list

Im trying to return an arraylist from the method getNumbers (which contains strings)
public ArrayList<String> getNumbers(){
return (numeros);
}
Then by using a searcher im trying to compare between a variable m (which contains the desired info to look for) and the returned list.
public class NumberSearcher {
Reader reader = new KeyboardReader();
public NumberSearcher(ArrayList<Contacto> contactos){
String m = reader.read();
for(int i = 0; i<contactos.size();i++){
if(contactos.get(i).getPhoneNumbers().contains(m)){
contactos.get(i).display();
}
}
}
}
I have succeded in creating a searcher using this very same style but only when using methods that return String alone.
The problem is its not working. If there there would be a match it should display the contact information but it seem it isnt "comparing" properly because nothing happens.
It's difficult to understand what you're asking here. Your getNumbers method doesn't get called from the second code block, so I don't see where that is relating to anything. It's also unclear what you mean the problem is. Can you try to give us a more detailed description of what is going wrong?
Anyways, I'll try to give you some general advice here, but without knowing the issue it's hard to say how much this will help.
Firstly, it is almost always recommended to have your method's return type as the List interface, rather than a specific implementation (ArrayList, etc). You can specify a return type from within the method but this way they client doesn't need to know what the underlying data structure is, and you are also flexible to future data structure changes.
public List<String> getNumbers(){
return (numeros);
}
Secondly, I would probably change the name 'getNumbers' to something slightly more precise - if I see a 'getNumbers' method I expect it to return some numeric entities, not a list of strings. If they are phone numbers then explicity call it 'getPhoneNumbers'.
Though I'm not entirely sure I understand what you asking, I think this may solve your issues:
for(int i = 0; i < contactos.size(); i++) {
Contacto next = contactos.get(i);
if(next.getEmails().contains(m)) {
next.display();
}
}
And as an afterthought, is there any specific reason you're only checking string containment? I would suggest that you check case-insensitive equality unless you really do want to find out if the string just contains the element.
Is this what you are looking for?
public class EmailSearcher {
Reader reader = new KeyboardReader();
public EmailSearcher(ArrayList<Contacto> contactos){
while(reader.read() != 'keyThatTerminates') {
String m = reader.read();
for(int i = 0; i<contactos.size();i++){
var row = contactos.get(i);
if(row.getEmails().contains(m)){
row.display();
}
}
}
}
}

how to retrieve object from java hashSet

I am looking for a way to retrieve object from hashSet in Java. I did iteration over its elements like this:
for (Customer remainingNode : availableNodes) {
remainingNode.setMarginalGain(calculateMarginalGain(
remainingNode, seedSet, network, availableNodes,
churnNet));
}
Unfortunately due to concurrent modification Exception I have to change that to something like this:
for(int i=0;i<numberofRemainingNodes;i++){
Customer remainingNode=availableNodes.get(i);
remainingNode.setMarginalGain(calculateMarginalGain(
remainingNode, seedSet, network, availableNodes,
churnNet));
numberofRemainingNodes=availableNodes.size();
}
But I can not do that because there is not any get(index) method for Java hashSet. Would you please help me to handle this situation?
P.S: I used HashSet because of I want to handle the union and intersection situation and I did not want to add duplicate element to that. Please consider that this part of my program should be run millions of times so a little extra latency could be expensive for whole program.
FYI:
private int calculateMarginalGain(Customer remainingNode,
HashSet<Customer> seedSet,
DirectedSparseGraph<Customer, Transaction> net,
Set<Customer> availableNodes, HashSet<Customer> churnNetwork) {
// Marginal gain for short-term campaign
HashSet<Customer> tmp = new HashSet<Customer>(); // seedset U
// {remainingNode}
tmp.add(remainingNode);
Set<Customer> tmpAvailableNodes = availableNodes;
HashSet<Customer> NeighborOfChurn = getNeighbors(churnNetwork, net);
// sigma function for calculating the expected number of influenced
// customers- seedSettmp=seedset U {u}
tmpAvailableNodes.removeAll(NeighborOfChurn);
Set<Customer> influencedNet = getNeighbors(tmp, net);
tmpAvailableNodes.retainAll(influencedNet);
return tmpAvailableNodes.size();
}
private HashSet<Customer> getNeighbors(HashSet<Customer> churnNetwork,
DirectedSparseGraph<Customer, Transaction> net) {
HashSet<Customer> churnNeighbors = churnNetwork;
Collection<Customer> neighbors = new HashSet<Customer>();
for (Customer node : churnNetwork) {
neighbors = net.getNeighbors(node);
for (Customer neighbor : neighbors) {
churnNeighbors.add(neighbor);
}
}
return churnNeighbors;
}
The problem in your code is that you change the structure of your HashSet during the iteration It is within the calculateMarginalGain() method, in this line:
tmpAvailableNodes.removeAll(NeighborOfChurn);
Think twice whether this is really right! If yes, then you can work easily around the problem by making you a copy of the set for the iteration first. E.g.:
Set<Customer> copy = new HashSet<Customer>;
copy.addAll(availableNodes);
for (Customer : copy) {
....
}
Actually tmpAvailableNodes and availableNodes are the identical set. Maybe you can improve here in general.
You have to use an Iterator:
Iterator<Customer> custIter = availableNodes.iterator();
while(custIter.hasNext()) {
Customer customer = custIter.next();
// do your work here
}
Using this you won't get ConcurrentModificationException. It is not clear why you get it though. If you are tampering with the HashSet from multiple Threads consider using a concurrent data structure instead.
If you modify availableNodes in setMarginalGain you will still get the exception though.

Creating method filters

In my code I have a List<Person>. Attributes to the objects in this list may include something along the lines of:
ID
First Name
Last Name
In a part of my application, I will be allowing the user to search for a specific person by using any combination of those three values. At the moment, I have a switch statement simply checking which fields are filled out, and calling the method designated for that combination of values.
i.e.:
switch typeOfSearch
if 0, lookById()
if 1, lookByIdAndName()
if 2, lookByFirstName()
and so on. There are actually 7 different types.
This makes me have one method for each statement. Is this a 'good' way to do this? Is there a way that I should use a parameter or some sort of 'filter'? It may not make a difference, but I'm coding this in Java.
You can do something more elgant with maps and interfaces. Try this for example,
interface LookUp{
lookUpBy(HttpRequest req);
}
Map<Integer, LookUp> map = new HashMap<Integer, LookUp>();
map.put(0, new LookUpById());
map.put(1, new LookUpByIdAndName());
...
in your controller then you can do
int type = Integer.parseInt(request.getParameter(type));
Person person = map.get(type).lookUpBy(request);
This way you can quickly look up the method with a map. Of course you can also use a long switch but I feel this is more manageable.
If good means "the language does it for me", no.
If good means 'readable', I would define in Person a method match() that returns true if the object matches your search criteria. Also, probably is a good way to create a method Criteria where you can encapsulate the criteria of search (which fields are you looking for and which value) and pass it to match(Criteria criteria).
This way of doing quickly becomes unmanageable, since the number of combinations quickly becomes huge.
Create a PersonFilter class having all the possible query parameters, and visit each person of the list :
private class PersonFilter {
private String id;
private String firstName;
private String lastName;
// constructor omitted
public boolean accept(Person p) {
if (this.id != null && !this.id.equals(p.getId()) {
return false;
}
if (this.firstName != null && !this.firstName.equals(p.getFirstName()) {
return false;
}
if (this.lastName != null && !this.lastName.equals(p.getLastName()) {
return false;
}
return true;
}
}
The filtering is now implemented by
public List<Person> filter(List<Person> list, PersonFilter filter) {
List<Person> result = new ArrayList<Person>();
for (Person p : list) {
if (filter.accept(p) {
result.add(p);
}
}
return result;
}
At some point you should take a look at something like Lucene which will give you the best scalability, manageability and performance for this type of searching. Not knowing the amount of data your dealing with I only recommend this for a longer term solution with a larger set of objects to search with. It's an amazing tool!

Categories