I have a List of Employee object.
class Employee{
private int empId;
private String name;
}
Now I have
List<Employee> empList = new ArrayList<Employee>();
How can I find, if my list contains an employee named "ABC"??
empList.contains("ABC"); wont work...
Should I put it in Map?? Which one is more efficient??
Just wanted to mention that I get my Employee object from database....
You can use
Map<String, Employee> map = new HashMap<>();
map.put("ABC", new Employee("ABC"));
map.put("John", new Employee("John"));
and then check
map.containsKey("ABC")
Should I put it in Map?? Which one is more efficient??
Because contains() method of list, calls indexOf, which needs to iterate over all elements
like this
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
Where as map no need to iterate over all elements
Since you are storing the Employee objects and not String in your list , i think it is impossible to search without looping through all list objects
for (Employee employee : empList) {
if (employee.getName().equals(searchString))
System.out.println("Found");
}
Note: Your Employee class should give access to name field either through getter method or change it to public
There are other alternatives, but it depends on your requirements and tradeoff's between speed, space, readability, resources etc
One thing i can think of is HashMap, which has constant time lookup in average case
HashMap<Integer, String> hm = new HashMap<Integer, String>();
hm.put(1, "Tom");
System.out.println(hm.containsValue("Tom"));
Now,
Should I put it in Map?? Which one is more efficient??
Instead of coding and analyzing, Know Thy Complexities beforehand !
In Java 8, if you wanted to determine whether the employee list contains an employee named "ABC", you could do this:
boolean containsABC = empList.stream().anyMatch(emp -> emp.getName().equals("ABC"));
Override equals. You can then use List.contains
class Employee {
private empId;
private name;
public boolean equals(Object o) {
return (o instanceof Employee && ((Employee)o).empId == empId && ((Employee)o).name = name);
}
}
List l = ...;
Employee e = new Employee(...);
l.add(e);
l.contains(e);
Here is the code that you can use.
I am considering that you want list to return true when empId and name of the Employee matches.
I also prefer to use Constructor in your code(Just recommendation).
The below code will run as you are wanting it to be.
class Employee {
private int empId;
private String name;
// below overriden function will return true if it found Employee with
// same ID and name
#Override
public boolean equals(Object obj) {
return (obj instanceof Employee //Checking instace of obj
&& ((Employee)obj).empId == empId //Checking empId
&& ((Employee)obj).name.equals(name)); //Checking name
}
// Used constructor to create Employee
Employee(int id, String nm) {
empId = id;
name = nm;
}
}
Here is an example run :
List l = new ArrayList();
l.add(new Employee(1, "ME");
System.out.println(l.contains(new Employee(1, "ME"))); //print true
I would also like to acknowledge you that you should also override hashCode() when you decides to override equals(...) method according to Design Pattern.
Related
I need to implement a method which should take an array of persons, basically public String oldest (Person [] persons), and return the oldest one. The persons which will be inputed are the following:
new Person("Augusta Ada King, grevinna av Lovelace", 1815),
new Person("Muhammad ibn Musa al-Khwarizmi", 780),
new Person("Alan Turing", 1912),
new Person("Grace Hopper", 1906)
Below you can find my class Called Person. I've tried all different solutions with basic for-loop but I feel really lost and would appreciate any input or recommendation how I should write the method to find the oldest person.
class Person {
String name;
int yearOfBirth;
public Person(String name, int yearOfBirth) {
this.name = name;
this.yearOfBirth = yearOfBirth;
}
public int getAge() {
return getAge(java.time.LocalDate.now().getYear());
}
public int getAge(int year) {
return year - yearOfBirth;
}
#Override
public String toString() {
return String.format("%s %d", name, yearOfBirth);
}
public String oldest(Person [] persons){
}
You can try this:
Person oldest = Arrays.stream(persons).max(Comparator.comparing(Person::getAge)).get();
You need to iterate over your persons array and check which yearOfBirth is greater. You can implement your method like below:
public String oldest(Person[] persons) {
Person oldestPerson = persons[0];
for (Person person : persons) {
if (person.getYearOfBirth() < oldestPerson.getYearOfBirth()) {
oldestPerson = person;
}
}
return oldestPerson.getName();
}
This method should be static since it has nothing to do with an instance, and otherwise you have to call the method from an instance, which you probably don't want to do
Want should happen if you have more then one (oldest) person with the same age?
Why should the return be only the name and not a Person?
public static String oldest(Person[] persons) {
if (persons == null){
throw new NullPointerException("persons == null");
}
if (persons.length == 0) {
return null; //or throw same Exception depending on your handling
}
Person oldestPerson = persons[0];
for (Person person : persons) {
if (person.yearOfBirth < oldestPerson.yearOfBirth) {
oldestPerson = person;
}
}
return oldestPerson.name;
}
Since there could be the possibility of more than one oldest person I would do it as follows:
Here is some data with two oldest people (sort of)
Person[] people = {
new Person("Augusta Ada King, grevinna av Lovelace",
1815),
new Person("Muhammad ibn Musa al-Khwarizmi", 780),
new Person("Another oldest person", 780),
new Person("Alan Turing", 1912),
new Person("Grace Hopper", 1906) };
String s = Person.oldest(people);
System.out.println(s);
prints
Muhammad ibn Musa al-Khwarizmi
Another oldest person
first I would make the method static since it doesn't rely on instance fields but an array of instances.
I would use a map to facilitate holding the the names of the people using their age as the key. Use the Map.merge method to populate the map and handle duplicate ages
Now iterate thru the names and as you do so:
find the oldest age.
store the name as the value for that age.
if another is found of the same age, concatenate the name with a newline(\n) and update the current map value.
when finished, return the value for the computed oldest individual(s).
public static String oldest(Person[] persons) {
int oldest = 0;
Map<Integer, String> ages = new HashMap<>();
for (Person p : persons) {
int age = p.getAge();
oldest = Math.max(oldest, age);
ages.merge(age, p.name, (last, current)- > last + "\n" + current);
}
return ages.get(oldest);
}
In case you would rather return a List of names your method can look like this. The main differences are:
return a List<String> which contains the names
using a Map<Integer, List<String>> to contain the people based on age.
computeIfAbsent to initialize the maps value for that age one time and then add the name to the list.
public static List<String> oldest(Person[] persons) {
int oldest = 0;
Map<Integer, List<String>> ages = new HashMap<>();
for (Person p : persons) {
int age = p.getAge();
oldest = Math.max(oldest, age);
ages.computeIfAbsent(age, v->new ArrayList<>()).add(p.name);
}
return ages.get(oldest);
}
It would then be called like so
List<String> list = Person.oldest(people);
list.foreach(System.out::println); // to print - same as before.
My final recommendation is that you use Lists over Arrays as they have advantages, the main on (imho) being that they grow dynamically as you add more items.
Suppose I have a class Employee :
class Employee {
Employee(String name, int age)
{
this.name = name ;
this.age = age;
}
String name ;
int age;
}
Now Create a List of this like :
ArrayList<Employee> aa = new ArrayList<Employee>();
aa.add(new Employee("Nitish", 26));
aa.add(new Employee("Sh", 2));
aa.add(new Employee("S", 1));
Can i get Employee Object Where name value is "Nitish"? Without For loop
I guess your interviewer just doesn't want you to use for or while loops to find objects in an ArrayList, but you can actually find them "without loops".
First, you need to override equals and hashCode of Employee class:
#Override public boolean equals(Object obj) {
// ...
}
#Override public int hashCode() {
// ...
}
Now you can find your object with ArrayList.indexOf (uses equals to find match) by creating a dummy reference:
Employee target = new Employee("Nitish", 26);
int index = employees.indexOf(target);
It's kinda silly but I guess some interviewers want us to think outside-of-the-box. Even though under the hood it's using loops, but if my interviewer asks me the same question, instead of saying no you can't, I'd use this example because I want to try my best just not to use "loops" as asked, and explains how it works behind the scene. Then afterwards I'd briefly come up with other better solutions, and hope that works!
You can use a filtered stream:
Object[] array = aa
.stream()
.parallel()
.filter((emp) -> emp.name.equals("Nitish"))
.toArray();
if (array.length > 0) {
Employee employee = (Employee)array[0];
String name = employee.name;
int age = employee.age;
System.out.println("Found Employee with Name = " + name + " and Age = " + age);
} else {
System.out.println("Not Found");
}
Try this
Employee emp = aa.stream().filter(e->e.name.equals("Nitish")).findAny().orElse(null);
this version returns null if not found
ArrayList work on index based structure.to ADD,READ,GET value from array need to index of the specific index.
instead store data on ArrayList you can use Map.
Using key can be access value from Map.
Map<String, Employee> employeeMap = new HashMap<>();
employeeMap.put("Nitish", new Employee("Nitish", 26));
employeeMap.put("Sh", new Employee("Sh", 2));
employeeMap.put("S", new Employee("S", 1));
System.out.println(employeeMap.get("Nitish").getName());
System.out.println(employeeMap.get("Nitish").getAge());
I have a shopping site, in which items can be added to a basket, each item is an instance of a class Product, and all the items are stored in a Collection<Product> items,
I am currently then iterating through that list and displaying each item in a table.
However I want to display a quantity value for each item instead.
I created a Map, and am trying to put each of my products into it.
However each Product is still listed as only existing once because each class instance is different?
How would I adjust this?
My Product class has a product ID value. Here's the code I have currently.
Map<Product, Integer> map = new HashMap<>();
for (Product p : items) {
Integer i = map.get(p);
if (i == null) {
map.put(p, 1);
}
else {
map.put(p, i+1);
}
}
Having implemented hashcode and equals methods.
Trying to add the items to the map.
Collection<Product> items = basket.getItems();
Map<Product, Integer> map = new HashMap<>();
for (Product p : items) {
for (Product key : map.keySet()) {
if (p.equals(key)) {
map.put(key, map.get(key));
}
else {
map.put(p, 1);
}
}
}
However each Product is still listed as only existing once because each class instance is different?
Yes.
HashMap identifies keys by using their implementation of hashcode() and equals().
You you either use a property, which already has a proper implementation of both (as #zsmb13 suggested) or you create implementations of hashcode() and equals() in your Product class (ATTENTION! do not inherit them! They must be implemented in a decent child which will not be extended itself...).
You need to override the equals and the hashCode of Product Class for your hashing based operations to function properly. You need your Product class something like this
class Product{
private int price;
private String name;
public Product(String itm, int pr){
this.name = itm;
this.price = pr;
}
public int hashCode(){
int hashcode = 0;
hashcode = price*20;
hashcode += name.hashCode();
return hashcode;
}
public boolean equals(Object obj){
if (obj instanceof Product) {
Product pp = (Product) obj;
return (pp.name.equals(this.name) && pp.price == this.price);
} else {
return false;
}
}
}
Sorry if the title isn't clear, I wasn't sure how to word it. I have an arraylist of objects and within each of these objects I store an integer value referring to a category and one referring to an ID.
I want to find the number of unique combinations of category and IDs that there are.
So at the moment I have
for(Object object: listofObjects){
//For each unique type of object.getID
//For each unique type of object.getCategory
//Add 1 to counter
}
I can't figure out how to do this. Doing things like for(int cat: object.getCategory()) brings up an error.
I can add the values to a new list within the initial for each loop like so,
ArrayList<Integer> aList= new ArrayList<Integer>();
for (Object object : spriteExplore) {
aList.add(object.getCategory());
}
for (int cat : aList) {
testCounter++;
}
but this obviosuly does not take into account uniqueness and also makes it awkward for factoring in the other variable of ID.
I feel like there is probably some easier work around that I am missing. Any advice?
Thanks in advance.
So you list of UserDefine object in ArrayList and you want to find unique Object.Just create set from list.
For e.g Suppose you have
List<Customer> list=new ArrayList<Custeomer>();
list.add(new Customer("A",12));
list.add(new Customer("B",13));
list.add(new Customer("A",12));
now
create set From this list
Set<Customer> set = new HashSet<Customer>(list);
this will have unique Customer
IMP : dont forget to override equals and hashcode method for Customer
Your best approach would be storing the data correctly.
It's possible that you still need to store non-unique items, if that's so - continue using an ArrayList, but in addition, use the following:
Override the hashcode & equels function as shown in this link:
What issues should be considered when overriding equals and hashCode in Java?
Then, use a Set (HashSet would probably be enough for you) to store all your objects. This data structure will disregard elements which are not unique to elements already inside the set.
Then, all you need to do is query the size of the set, and that gives you the amount of unique elements in the list.
I don't know any library that does this automatically, but you can do it manually using sets. Sets will retain only unique object so if you try to add the same value twice it will only keep one reference.
Set<Integer> categories = new HashSet<Integer>();
Set<Integer> ids= new HashSet<Integer>();
for (Object object : listofObjects) {
categories.add(object.getCategory());
ids.add(object.getID());
}
Then you get the number of unique categories / ids by doing
categories.size()
ids.size()
And all your unique values are stored in the sets if you want to use them.
I would look into using a (Hash)Map<Integer, Integer>. Then just have 1 foreach loop, checking to see if the value of Map<object.getId(), object.getCategory()> is null by checking if map.get(object.getId()) is null - if it is, then this pair does not exist yet, so add this pair into the map by using map.put(object.getId(), object.getCategory()). If not, do nothing. Then at the end, to find the number of unique pairs you can just use map.size()
Hope this helps
Map<Integer,List<Integer>> uniqueCombinations = new HashMap<Integer,List<Integer>>();
for (Object object : listofObjects) {
if(uniqueCombinations.get(object.getCategoryId())==null) {
uniqueCombinations.put(object.getCategoryId(), new LinkedList<Integer>);
}
uniqueCombinations.get(object.getCategoryId()).add(object.getId());
}
return uniqueCombinations.size()
I believe you want unique combinations of both category and id, right?
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class SO {
class MyObject{
private int id;
private int category;
private String name;
private MyObject(int id, int category,String name) {
super();
this.id = id;
this.category = category;
this.name = name;
}
protected int getId() {
return id;
}
protected int getCategory() {
return category;
}
#Override
public String toString() {
return "MyObject [id=" + id + ", category=" + category + ", name=" + name + "]";
}
}
public static void main(String[] args) {
SO so = new SO();
List<Object> listofObjects = new ArrayList<Object>();
listofObjects.add(so.new MyObject(1,1,"One"));
listofObjects.add(so.new MyObject(1,1,"Two"));
listofObjects.add(so.new MyObject(1,2,"Three"));
Map<String,List<MyObject>> combinations = new HashMap<String,List<MyObject>>();
for(Object object: listofObjects ){
//For each unique type of object.getID
//For each unique type of object.getCategory
//Add 1 to counter
if (object instanceof MyObject){
MyObject obj = (MyObject)object;
String unique = obj.id+"-"+obj.category;
if (combinations.get(unique) == null){
combinations.put(unique, new ArrayList<MyObject>());
}
combinations.get(unique).add(obj);
}
}
System.out.println(combinations);
//counts
for(Entry<String,List<MyObject>> entry:combinations.entrySet()){
System.out.println(entry.getKey()+"="+entry.getValue().size());
}
}
}
Use the Hashmap to save occurence. Dont forget to implement hashcode und equals Methods. You can generate them if you work with Eclipse IDE.
public static void main(String[] args) {
List<MyObject> myObjects = Arrays.asList(new MyObject(1, 2), new MyObject(2, 3), new MyObject(3, 4), new MyObject(3, 4));
Map<MyObject, Integer> map = new HashMap<>();
for (MyObject myObject : myObjects) {
Integer counter = map.get(myObject);
if(counter == null){
counter = 1;
} else {
counter = counter + 1;
}
map.put(myObject, counter);
}
long uniqueness = 0;
for(Integer i : map.values()){
if(i == 1){
++uniqueness;
}
}
System.out.println(uniqueness);
}
The last part can be replaced by this one line expression if you are working with Java 8:
long uniqueness = map.values().stream().filter(i -> i == 1).count();
I wrote a class that is to be stored in a linkedlist, with 3 fields in the class. One of these fields is a String, which I would like to search for in the linked list.
Example
LinkedList
Obj1
String name = "first";
int age = 2;
int size = 4;
Obj2
String name = "second";
int age = 3;
int size = 6;
Obj3
String name = "third";
int age = 5;
int size = 8;
If this is the linkedlist storing these three objects with the given fields, is there a way to search the linked list for the object with the name "second"?
You can search for an item in the list by iteration
// Iterate over each object within the list
for(YourClass obj : yourLinkedList) {
// Check if the object's name matches the criteria, in this case, the name
// of the object has to match "second"
if (obj.name.equals("second")) {
// If we are within this block, it means that we found the object that has
// its name set as "second".
return obj;
}
}
You could also make a method to make things more elegant
public YourClass findByName(String name) {
for(YourClass obj : yourLinkedList) {
if (obj.name.equals(name)) {
return obj;
}
}
return null;
}
And use it the following way
YourClass object = findByName("second");
The easiest way to do this would be to of course, iterate through each element in the collection, checking if it matched your filter condition, and selecting the matches found. However this gets tedious the more times you need to do it, and the more complex your filter condition is. I would recommend utilizing pre-existing libraries to get the task done efficiently. Here is an example using Google-Collections:
final List<SomeObj> listObjs = Arrays.asList(
new SomeObj("first", 2, 4), new SomeObj("second", 3, 6),
new SomeObj("third", 5, 8));
final Iterable<SomeObj> filtered = Iterables.filter(listObjs,
new Predicate<SomeObj>() {
#Override
public boolean apply(final SomeObj obj) {
return "second".equals(obj.getName());
}
});
for (final SomeObj obj : filtered) {
System.out.println(obj);
}
The code shown would select all objects in the list with a name property of "second". Obviously, the predicate doesn't have to be an anonymous inner class - if you needed to reuse it you would just break it out to a standalone class.
Here's another way to implement a Comparator (just in case it helps).
I find it's easier to understand if you implement the Comparator explicitly:
class PersonAgeComparator implements Comparator<Person> {
#Override
public int compare(Person p1, Person person2) {
return p1.getAge().compareTo(p2.getAge());
}
}
You might use the above like this:
Comparator ageComparator = new PersonAgeComparator();
List<Person> personList = // populate list somehow
Person fourYearOld = new Person();
fourYearOld.setAge(4);
for (Person p : personList) {
if (ageComparator.compare(fourYearOld, p) == 0) {
System.out.println(p.getName() + " is 4 years old");
}
}
This doesn't make much sense for this simple example.
It would be ideal if you had several complicated ways to compare people (by height, by adjusted income, by how many states they've lived in, etc...).
Take a look at the java.util.Comprator interface. You can write a method that iterates over a List and uses a comparator to find the one you are after.
Something like (not compiled):
for(final T value : list)
{
if(comparator.compare(value, desired) == 0)
{
// match
}
}
In your comparator you have it perform whatever comparison you want.
Here is a working example:
public class JavaApplication4
{
public static void main(String[] args)
{
final List<Data> list;
final List<Data> a;
final List<Data> b;
list = new ArrayList<Data>();
list.add(new Data("Foo", 1));
list.add(new Data("Bar", 10));
list.add(new Data("Car", 10));
a = find(list,
new Data("Bar", 0),
new Comparator<Data>()
{
#Override
public int compare(final Data o1,
final Data o2)
{
return (o1.name.compareTo(o2.name));
}
});
b = find(list,
new Data(null, 10),
new Comparator<Data>()
{
#Override
public int compare(final Data o1,
final Data o2)
{
return (o1.count - o2.count);
}
});
System.out.println(a.size());
System.out.println(b.size());
}
private static List<Data> find(final List<Data> list,
final Data desired,
final Comparator<Data> comprator)
{
final List<Data> results;
results = new ArrayList(list.size());
for(final Data data : list)
{
if(comprator.compare(desired, data) == 0)
{
results.add(data);
}
}
return (results);
}
private static class Data
{
private final String name;
private final int count;
Data(final String nm,
final int c)
{
name = nm;
count = c;
}
}
}
And here is a generic version of the find method. Using this method you would never have to write the find method again, using a method that embeds the logic for matching in the iteration code means that you would have to re-write the iteration logic for each new set of matching logic.
private static <T> List<T> find(final List<T> list,
final T desired,
final Comparator<T> comprator)
{
final List<T> results;
results = new ArrayList(list.size());
for(final T value : list)
{
if(comprator.compare(desired, value) == 0)
{
results.add(value);
}
}
return (results);
}
You can go through it and get it done or there's another way.
You need to override the equals method in your class (and the hashcode method as well).
After you override the equals to your desire, in this case to compare the names, create a new object with the same name and call the remove(Object o) method of the LinkedList and get the object.
You should note that with this approach you objects equality will be defined by name and that the entry will be removed from the LinkedList