I have two array lists that store instances of a class called Book. I am trying to get the book/books that is inside both lists.
This is a search feature that allows you to search for a book by entering the book's ISBN, Name and Author. The list 'resultA' contains the books with the inputted ISBN and Name while the other list 'resultB' contains the books written by the inputted author. To get the final result I need to get the book that is inside both arrays.
I have tried using the retainAll() function but I found that it doesn't work on lists with instances stored.
List<Book> resultA = BookManager.getBooksWhere("book_ISBN", ISBN, "book_name", bookName);
List<Book> resultB = BookManager.getBooksByAuthors(authors);
resultB.retainAll(resultA);
searchResults = resultA;
Is there some other function I can use instead to get the common book?
(Update)
Sorry, Here is the Book class:
public class Book
{
private int bookID;
private String bookISBN;
private String category;
private int libId;
private String name;
#Override
public String toString()
{
String output = bookISBN + " - " + name + " - " + category + " - ";
return output;
}
public int getBookID()
{
return bookID;
}
public void setBookID(int bookID)
{
this.bookID = bookID;
}
public String getBookISBN()
{
return bookISBN;
}
public void setBookISBN(String bookISBN)
{
this.bookISBN = bookISBN;
}
public int getLibId()
{
return libId;
}
public void setLibId(int libId)
{
this.libId = libId;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
(Update)
I did not know that I had to override the Books class for this to work and thanks for pointing that out DNA and pbabcdefp. I have looked up on how to do it and it has worked correctly, the common book is being taken out from both lists.
This was inserted in the book class and uses their unique id to compare if books are equal.
#Override
public boolean equals(Object o)
{
if (o == null)
return false;
if (getClass() != o.getClass())
return false;
final Book otherBook = (Book) o;
if (this.bookId != otherBook.bookId)
{
return false;
}
return true;
}
Assuming you defined an equals function for the Book class, here is a function that can get the common elements in two arrays:
public static <T> List<T> getCommonElements(List<T> list1, List<T> list2) {
List<T> resultsList = new ArrayList<>();
for (T element1: list1) {
for (T element2: list2) {
if (element1.equals(element2)) {
resultsList.add(element2);
}
}
}
return resultsList;
}
This looks like a school question. With that, I doubt you are looking for an answer with generics or comparators or overriding the compareTo or equal method.
Hence, this is what you can do:
for(int x=0; x<listA.size(); x++)
for(int y=0; y<listB.size(); y++)
if(listA.get(x).getISBN().equals(listB.get(y).getISBN()))
return listA.get(x);
Instead of using equals to compare, you get use their ISBN which is supposed to be their unique id. Alternatively, you can override the equals method within the Book class to compare the ISBN.
Related
i use 2 implementations of Set:HashSet and TreeSet.I added 10 elements to set and find object by contains method from set.I see that contains method iterate all of the objects although it found element.For performance reason i confused.Why it is so and how can i prevent it?
I have a Person class:
public class Person implements Comparable<Person>{
private int id;
private String name;
public Person() {
}
public Person(int id, String name) {
this.id = id;
this.name = name;
}
//getter and setters
#Override
public int hashCode() {
System.out.println("hashcode:" + toString());
return this.id;
}
#Override
public boolean equals(Object obj) {
System.out.println("equals:" + toString());
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Person other = (Person) obj;
return true;
}
#Override
public String toString() {
return "Person{" + "id=" + id + ", name=" + name + '}';
}
#Override
public int compareTo(Person o) {
System.out.println("compare to:"+getId()+" "+o.getId());
if(o.getId() == getId()){
return 0;
}else if(o.getId()>getId()){
return -1;
}else {
return 1;
}
}
}
And in main class i add 10 Person object and then call contains method by first element of set:
import beans.Person;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Set<Person> people = new HashSet<>();
for (int i = 0; i < 10; i++) {
people.add(new Person(i, String.valueOf(i)));
}
Person find = people.iterator().next();
if (people.contains(find)) {
System.out.println("here"+find.getName());
}
}
}
And result:
hashcode:Person{id=0, name=0} <--here element has been found but it continues
hashcode:Person{id=1, name=1}
hashcode:Person{id=2, name=2}
hashcode:Person{id=3, name=3}
hashcode:Person{id=4, name=4}
hashcode:Person{id=5, name=5}
hashcode:Person{id=6, name=6}
hashcode:Person{id=7, name=7}
hashcode:Person{id=8, name=8}
hashcode:Person{id=9, name=9}
hashcode:Person{id=0, name=0}<-- second check
here:0
Your equals() method is wrong. It returns true whatever the other person is.
It doesn't respect the contract of equals(), BTW, since equal objects should have an equal hashCode, and the hashCode is the ID of the person. So two persons with different IDs have a different hashCode, but are still equal.
That said, your test shows that hashCode() is executed 10 times. But it's not executed by contains(). It's executed by add(). Every time you add an object to the set, its hashCode() is used to know which bucket should hold the object.
It doesn't iterate though all elements. The reason the hashcode is bring printed for each object is because the hashcode needs to be calculated when Inserting into the set.
The first 10 prints are perhaps for the insert code and last one for the contains call. I hope that is the thing which might be confusing you.
This question already has answers here:
How do define my own element class for use with Set
(2 answers)
Why should a Java class implement comparable?
(10 answers)
Closed 6 years ago.
I have a simple class called Stock the code is listed below, and I my requirement is to create a Collection of Stock where the combination of the fields StockId, Code and name should be unique, I am doing this by implementing my own list class. I was wondering if there is any better way to do this
public class Stock {
private Integer stockId;
private String stockCode;
private String stockName;
public Stock() {
}
public Stock(Integer stockId,String stockCode, String stockName) {
this.stockCode = stockCode;
this.stockName = stockName;
}
public Integer getStockId() {
return this.stockId;
}
public void setStockId(Integer stockId) {
this.stockId = stockId;
}
public String getStockCode() {
return this.stockCode;
}
public void setStockCode(String stockCode) {
this.stockCode = stockCode;
}
public String getStockName() {
return this.stockName;
}
public void setStockName(String stockName) {
this.stockName = stockName;
}
}
List class
public class StockList {
private List<Stock> listStock;
public StockList(){
listStock = new ArrayList<Stock>();
}
public void add(Stock stock){
boolean result=true;
for(Stock st:listStock){
int count=0;
if(st.getStockId()==stock.getStockId()){
count++;
}
if(st.getStockCode()==stock.getStockCode()){
count++;
}
if(st.getStockName()==stock.getStockName()){
count++;
}
if(count>=3){
result=false;
break;
}
}
if(result) {
listStock.add(stock);
}
}
public List<Stock> getList(){
return listStock;
}
}
I have even tried the Hashset per instructions but it still let me add two Stock objects with same values in every field
import java.util.HashSet;
import java.util.Set;
public class Stock {
private Integer stockId;
private String stockCode;
private String stockName;
public Stock() {
}
public Stock(Integer stockId,String stockCode, String stockName) {
this.stockCode = stockCode;
this.stockName = stockName;
}
public Integer getStockId() {
return this.stockId;
}
public void setStockId(Integer stockId) {
this.stockId = stockId;
}
public String getStockCode() {
return this.stockCode;
}
public void setStockCode(String stockCode) {
this.stockCode = stockCode;
}
public String getStockName() {
return this.stockName;
}
public void setStockName(String stockName) {
this.stockName = stockName;
}
public int hashCode() {
final int PRIME = 31;
int result = 1;
result = PRIME * result + stockId+stockCode.hashCode()+stockName.hashCode();
return result;
}
public boolean equals(Object obj) {
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Stock other = (Stock) obj;
int count=0;
if (stockId == other.stockId){
count++;
}
if(stockCode.equalsIgnoreCase(other.stockCode)){
count++;
}
if(stockName.equalsIgnoreCase(other.stockName)){
count++;
}
if(count<3) {
return true;
}
return false;
}
}
You will need to add your Stock objects in a HashSet<Stock>.
Before adding a Stock object to the set, you will be able to check whether the HashSet already contains it by invoking myStockHashSet.contains( stock ). (But even if you go ahead and add a duplicate stock object to the HashSet, the new object will not replace the old object, so there will never be duplicates.)
In order for HashSet to work, it has to be able to tell whether two Stock objects are identical. For this, your Stock class will need to implement hashCode() and equals().
hashCode() will need to hash together the fields stockId, code and name. Recent versions of java offer an Objects.hashCode( Object ... ) convenience method for quickly hashing together your fields. If you are not programming against a recent version of java, you will need to write your own implementation of a hashCode() calculation. Look here for some good advice: Best implementation for hashCode method
equals() should return true only if all these fields are equal in both objects.
NOTE:
do not waste your time with a List, since lists allow duplicates.
do not waste your time implementing Comparable, since this is for ordering objects, not for comparing objects for equality, and HashSet does not care whether your objects implement Comparable.
As you will probably see from my code I'm quite new with this. I am trying to write a simple program to retrieve the friends of one person. Here is my code:
public class Person {
private String name;
private String friends;
public Person(String aName) {
name = aName;
friends = "";
}
public String getFriends() {
return friends;
}
public void addFriend(Person friend) {
friends = friends + " " + friend.name;
}
public void unfriend(Person nonFriend) {
friends = friends.replace(" " + nonFriend.name, "");
}
public static void main(String[] args) {
Person dana = new Person("Dana");
Person gina = new Person("Gina");
Person john = new Person("John");
dana.addFriend(gina);
dana.addFriend(john);
john.addFriend(gina);
john.addFriend(dana);
john.unfriend(dana);
System.out.println("Dana's friends are: " + dana.getFriends());
System.out.println("Gina's friends are: " + gina.getFriends());
System.out.println("John's friends are: " + john.getFriends());
}
}
Everything works, but I do not know how to create a method that will say:
If Gina is both Dana's and John's friend then clearly Gina's friends will be Dana and John. I know that I can add two lines there gina.addFriend(dana) and gina.addFriend(john), to accomplish the same result, but I would like to know what will the method be for that. Thanks in advance.
First of all, make friends an ArrayList<Friend>.
private ArrayList<Friend> friends;
This has several advantages, including being easier to use and storing the Persons themselves rather than just their names.
Then, change the addFriend method to go in both directions:
public void addFriend(Person friend) {
friends.add(friend);
friend.friends.add(this);
}
In this way, friendships will automatically go back and forth. You should also change unfriend:
public void unFriend(Person friend) {
friends.remove(friend);
friend.friends.remove(this);
}
EDIT: as per a comment above, a set would actually be better, as it can only have one of each value.
I would use a Set, and add a unique Id to person to get around the problem of multiple people having the same name.
Your class will then look like:
public class Person
{
private final String personId;
private final String name;
private final Set<Person> friends;
public Person(String personId, String name) {
super();
this.personId = personId;
this.name = name;
this.friends = new HashSet<Person>();
}
public void addFriend(Person friend) {
if(friend != null && !friends.contains(friend)) {
this.friends.add(friend);
// Optional : if it is a two-way relationship that doesn't need approving etc
friend.addFriend(this);
}
}
public void unfriend(Person nonFriend)
{
if(nonFriend != null && friends.contains(nonFriend)) {
this.friends.remove(nonFriend);
// Optional : if it is a two-way relationship that doesn't need approving etc
nonFriend.unfriend(this);
}
}
public Set<Person> getFriends()
{
return friends;
}
#Override
public String toString() {
return "Person [name=" + name + "]";
}
public static void main(String[] args)
{
Person dana = new Person("D001", "Dana");
Person gina = new Person("G001", "Gina");
Person john = new Person("J001", "John");
dana.addFriend(gina);
dana.addFriend(john);
john.addFriend(gina);
john.addFriend(dana);
john.unfriend(dana);
System.out.println("Dana's friends are: "+dana.getFriends());
System.out.println("Gina's friends are: "+gina.getFriends());
System.out.println("John's friends are: "+john.getFriends());
}
// Equals and Hashcode are very important when using 'contains' and other Set-based methods
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((personId == null) ? 0 : personId.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (personId == null) {
if (other.personId != null)
return false;
} else if (!personId.equals(other.personId))
return false;
return true;
}
}
i would suggest to use an arrayList of persons/friends instead of one string.
ArrayList<Person> friends = new ArrayList<Person>;
you add friends by typing:
public void addFriend(Person newFriend){
friends.add(newFriend);
newFriend.friends.add(this);
}
you delete friends by typing:
public void unfriend(Person noFriend){
for(int i = 0; i < this.friends.size(); i++){
if(this.friends.get(i).name.equals(noFriend.name){
this.friends.delete(i);
}
}
for(int i = 0; i < noFriend.friends.size(); i++){
if(noFriend.friends.get(i).name.equals(this.name){
noFriend.friends.delete(i);
}
}
}
to show the whole list of friends:
public void showFriends(){
for(int i = 0; i < this.friends.size(); i++){
System.out.println(this.friends.get(i));
}
}
Struggling with a little project I've set myself to learn Java. My goal is to create a program to store a list of Car objects. Then to allow the user to search for a particular car and output all of them if they exist. The car object should contain model name, registration number, vin and colour. Here is what I have so far:
package carObjects;
public class cars {
public static int length;
private String modelName;
private String carColour;
private int regNumber;
private int vin;
public cars(String string, String string2, int i) {
}
public String toString() {
return "Model Name: " + modelName + "Registration Number: " + regNumber
+ "Vin" + vin + "Car Colour: " + carColour;
}
public String getLast() {
return modelName;
}
}
for (int i = 0; i < cars.length; i++) {
cars[i] = new cars("A", "B", 10);
}
for (cars p : cars) {
System.out.println(p.getLast());
}
}
}
Here are some of the things you would need to do:
Since you want to allow searching, you will need to expose accessors to the properties which you would like the user to search for. For instance, if you want to allow users to search by model, you will need to expose the model property. You seem to be doing this through the getLast() method, however, the name is confusing.*
The problem with this code: for (int i = 0; i < cars.length; i++) {
cars[i] = new cars("A", "B", 10);
}
Is that it is creating a series of identical objects. You could use the value of i to provide some dummy, changing values. This will allow you to test that your search is indeed working.
Constructor names should start with an upper case, just like class names.
cars(String string, String string2, int i): Please provide meaningful names to your variables. This will make your code easier to read.
You will need to assign the variables you are getting through your constructor. As is, at the moment your fields will not be initialized to what you are providing.
To create a 2D array, you will need to use the following syntax: Car[][] carArr = new Car[5][5]. This will create a 5x5 array of type car. To iterate over it, you will need to use a nested loop:
for(int i = 0; i < carrArr.length; i++) {
for (int j = 0; j < carrArr[i].lenght;j++) {
...
}
}
* The usage of getters and setters allow you to control which object properties are exposed and how can users interact with them.
The best would be to separate your exercise in two different classes:
class Car {
private String modelName;
private String carColour;
private int regNumber;
private int vin;
public int getVin() {
return vin;
}
public void setVin(int vin) {
this.vin = vin;
}
// other getter/setter
#Override
public String toString() {
return "Car: " + getVin();
}
#Override
public int hashCode() {
return vin;
}
#Override
public boolean equals(Object obj) {
return (obj != null)
&& (obj instanceof Car)
&& ((Car) obj).getVin() == this.getVin();
}
}
CarSet class has the searching methods:
class CarList extends HashSet<Car> {
public Car serarchByVin(int vin) {
List<Car> list = new ArrayList<>(this);
for (Car c : list) {
if (c.getVin() == vin) {
return c;
}
}
return null;
}
public CarSet searchByModel(String model) {
CarSet result = new CarSet();
List<Car> list = new ArrayList<>(this);
for (Car c : list) {
if (c.getModelName()== model) {
result.add(c);
}
}
return result;
}
#Override
public String toString() {
String result = "carList: ";
for (Car c : this) {
result += c;
}
return result;
}
}
I have
String selectedName = "ABC";
List<object> pgetName;
where object has variables such as id, name, version
I want to do the equivalent of
int first = pgetName.indexOf(selectedName);
int last = pgetName.lastIndexOf(selectedName);
as used for simple String Arrays. I've tried
int first = pgetName.getProperty("name").indexOf(processToStart);
and
int first = pgetName[].getName().indexOf(processToStart);
for example but they don't work. How do I do what I want to do? This is advanced Java for me being a noob...
Thanks in advance,
Here's an other approach (might be a little overkill but it shows you an other way). The idea is to override the indexOf and lastIndexOf method so it would verify against your field "name":
private static class TestObject {
String id, name, version;
public TestObject(String id, String name, String version) {
super();
this.id = id;
this.name = name;
this.version = version;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public String getVersion() {
return version;
}
}
public static void main(String[] args) {
List<TestObject> pgetName = new ArrayList<TestObject>() {
#Override
public int indexOf(Object o) {
if (o == null || this.isEmpty()) {
return -1;
}
int counter=0;
for (TestObject current : this) {
if (o.equals(current.getName())) {
return counter;
}
counter++;
}
return -1;
}
#Override
public int lastIndexOf(Object o) {
if (o == null || this.isEmpty()) {
return -1;
}
for (int i=this.size()-1; i>=0;i--) {
TestObject current = get(i);
if (o.equals(current.getName())) {
return i;
}
}
return -1;
}
};
pgetName.add(new TestObject("1", "name1", "ver1"));
pgetName.add(new TestObject("2", "name2", "ver2"));
pgetName.add(new TestObject("3", "name3", "ver3"));
pgetName.add(new TestObject("4", "name1", "ver4"));
int first = pgetName.indexOf("name1");
int last = pgetName.lastIndexOf("name1");
System.out.println("First: " + first + " - Last: " + last);
}
Result is:
First: 0 - Last: 3
For any Java object you can override the methods equals and hashCode (this is not really used but it is generally a good practice to implement both methods) in order to use the indexOf and lastIndexOf functions of java.util.List.
The contextual menu of eclipse generates a default implementation of both methods, letting you choose on which field the comparison should be done. Give it a try.
After the implementation of the methods above, you can use indexOf on List.
If I understand your question, you want to "find the index of an Object where one of the properties of the object is a specific value".
This isn't directly possible in Java (or most languages FWIW). You can achieve it pretty simply with a for loop, however:
public MyObject findObjectByName(MyObject[] objects, String name) {
for (MyObject object: objects) {
if (object.name.equal(name) {
return object;
}
}
return null;
}
If you want to find the index, you can do something similar:
public int findObjectIndex(MyObject[] objects, String name) {
for (int i = 0; i < objects.length; ++i)
if (objects[i].name.equal(name) {
return i;
}
}
return -1;
}
Now, this is the most naive approach you can take, and is often, but not always, the best approach. If you have a large number of objects, and you need to look up a lot by name, then you could be better off building an index once, and then look them up by the index:
public class MyObjectIndex {
final Map<String, MyObject> byName = new HashMap<String, MyObject>();
public MyObjectIndex(MyObject[] objects) {
for (MyObject object: objects) {
byName.put(object.getName(), object);
}
}
public getMyObjectWithName(String name) {
return byName.get(name);
}
}