I have two different ArrayList instances, one of type Container and one of type String. The first is a list of "banned goods" (strings) for a country, and the other is a list of containers on a ship. The ship travels through the country, and the containers are searched for the banned goods. If the container contains the banned goods, that container should be removed/deleted.
public Customs(String country)
{
countryName = country;
bannedGoods = new ArrayList<String>();
}
public Ship(String n, double weight)
{
emptyWeight = totalWeight = weight;
name = n;
containers = new ArrayList<Container>();
}
I already have a method in the Ship class that removes the container:
public void removeContainer(int i)
{
if(i >= 0 && i < containers.size()) {
Container r = containers.remove(i);
totalWeight = totalWeight - r.getWeight();
}
}
I am trying to create an method to inspect the ship for the containers. I want to use two for-loops for each of the arrays, but I can't seem to get it right! Can someone help me use the two loops to search the arrays? Additionally, I think that I will need to use an iterator (the remove function, specifically) in the loop, but that is also confusing for me. Should the iterator remove method replace the method I already wrote in class ship? Here is what I have:
public void inspect(Ship ship)
{
for (String good : bannedGoods) {
for (String con : containers) {
if (con.contains(good) {
container.remove();
}
}
}
And here is my attempt at the iterator:
for(String good : bannedGoods) {
Iterator<String> it = ship.containers.iterator();
while (it.hasNext())
if (ship.contains(good))
it.remove();
}
I don't think you need 2 for loops. You should iterate over banned goods & simply remove it from the containers.
Also, Assuming that containers list is of type string as this is mentioned in your fist line : I have two different arrayLists of the same type String
public void inspect(Ship ship, ArrayList<String> bannedGoods){
if (ship == null || bannedGoods == null || bannedGoods.isEmpty())
return;
for(String good : bannedGoods){
ship.containers.remove(good);
}
}
If, Containers is of type Container and it contains a list of containers(Arraylist of string) which is accessible via the method get_containers(), the following would work:
public void inspect(Ship ship, ArrayList<String> bannedGoods){
if (ship == null || bannedGoods == null || bannedGoods.isEmpty())
return;
for(String good : bannedGoods){
for(Container container : ship.containers){
container.get_containers().remove(good);
}
}
}
You can stick to the methods you are using at the moment. But keep in mind that you either need to use the iterator's remove method or not use iterators. So to use your remove method, either implement Iterable or simply use indexes instead of iterators:
for (int i = 0; i < bannedGoods.size(); i++)
{
for (int j = 0; j < containers.size();) // NOTE: no j++ here
{
Container c = containers.get(j);
if (c.contains(bannedGoods.get(i))
c.removeContainer(j);
else
j++; // only if you don't remove the container increment
// j - when removing the next element gets current
// index
}
}
You're actually pretty close, and you've done a good job of focusing on object-oriented programming principles while designing your classes. I think the things you need to focus on now are just being more careful with your types. Below are some suggested modifications to your classes (Container isn't shown, but I'm assuming it has a public boolean contains (String s) method that checks whether the container has a certain good s inside.
import java.util.*;
public class Ship implements Iterable<Container> {
private double emptyWeight, totalWeight, weight;
private String name;
private List<Container> containers = new ArrayList<Container>();
public Ship(String n, double weight) {
emptyWeight = totalWeight = weight;
name = n;
}
private void removeContainer(int i) {
if (i >= 0 && i < containers.size()) {
Container r = containers.remove(i);
totalWeight = totalWeight - r.getWeight();
}
}
public Iterator<Container> iterator() {
return new Iterator<Container> {
private index = 0;
private Container previous = null;
public boolean hasNext() {
return index < containers.size();
}
public Container next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
previous = containers.get(index++);
return previous;
}
public void remove() {
if (previous == null) {
throw new IllegalStateException();
}
removeContainer(containers.indexOf(previous));
previous = null;
}
};
}
}
I suggest keeping removeContainer within your Ship class since it's responsible for keeping track of how its weight changes when a container is removed. For the same reason, don't allow external classes to directly access its containers list. That way you can prevent other code from adding or removing values from that list without updating the weight correctly. I'd suggest making the containers list private, and expose an Iterator to allow users of the class to interact with the containers.
Within your Customs class, you'd use the Iterator's remove method to remove offending Container instances:
import java.util.*;
public class Customs {
private String countryName;
private List<String> bannedGoods = new ArrayList<String>();
public Customs(String country) {
countryName = country;
}
public void inspect(Ship ship) {
for (String good : bannedGoods) {
for (Iterator<Container> it = ship.iterator(); it.hasNext();) {
Container container = it.next();
if (container.contains(good) {
it.remove();
}
}
}
}
}
Related
I have a Object which contains a list of another object which contains a list of another object and so on... suppose I want to get count of nested list elements(lets say last one), what should be best approach rather than using traditional for loop in java as I have done in below example -
public static void main(String[] args) {
Statement statement = new Statement();
statement.getInvAccount().add(new InvestmentAccount());
statement.getInvAccount().get(0).getSecAccountStmt().add(new SecurityStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
// method to count the number of TransactionStatement
System.out.println("Size of TransactionStatement is : " + count(statement));
}
private static int count(Statement stmt) {
int countOfTransStmt = 0;
for (InvestmentAccount invAcc : stmt.getInvAccount()) {
if (invAcc != null) {
for (SecurityStatement secStmt : invAcc.getSecAccountStmt()) {
if (secStmt != null) {
countOfTransStmt = countOfTransStmt + secStmt.getTransactionStatement().size();
}
}
}
}
return countOfTransStmt;
}
In Java 7 you're not going to do better than two for loops. I wouldn't bother with anything different.
In Java 8 you can use streams to flatten it out:
private static int count(Statement stmt) {
return stmt.getInvAccount().stream()
.filter(Objects::nonNull)
.flatMap(InvestmentAccount::getSecAccountStmt)
.filter(Objects::nonNull)
.flatMap(SecurityStatement::getTransactionStatement)
.count();
}
I would encourage you to get rid of the null checks. If you're going to ignore nulls, better to just expect them not to be inserted in the first place. It'll get rid of a lot of extra if checks throughout your code, I expect.
I'd also encourage you not to abbreviate your variables and methods. Spell out "statement" and "investment" and the like. The abbreviations are harder to read and the brevity isn't really a win.
Similarly, try to use more descriptive method names. countTransactions is better for the main method. And for the various getters, methods that return lists ought to be plural: "getAccounts" rather than "getAccount". Notice how the getters now match the class names; if you know the class name, you know the getter name. You don't have to guess if one or the other is abbreviated:
private static int countTransactions(Statement statement) {
return statement.getInvestmentAccounts().stream()
.flatMap(InvestmentAccount::getSecurityStatements)
.flatMap(SecurityStatement::getTransactionStatements)
.count();
}
Recursion could work in this case:
General idea below:
private int countTransactions(object t)
{
int sum = 0;
if (t == null) return 0;
for (int i = 0; i < t.getAllSub().count; i++)
{
sum += countTransactions(t.subAt(i));
}
return sum;
}
I'm sitting on an assignment for university and I'm at a point, where I fear I haven't really understood something fundamental in the concecpt of Java or OOP altogether. I'll try to make it as short as possible (maybe it's sufficient to just look at the 3rd code segment, but I just wanted to make sure, I included enough detail). I am to write a little employee management. One class within this project is the employeeManagement itself and this class should possess a method for sorting employees by first letter via bubblesort.
I have written 3 classes for this: The first one is "Employee", which contains a name and an ID (a running number) , getter and setter methods and one method for checking whether the first letter of one employee is smaller (lower in the alphabet) than the other. It looks like this:
static boolean isSmaller(Employee source, Employee target) {
char[] sourceArray = new char[source.name.length()];
char[] targetArray = new char[target.name.length()];
sourceArray = source.name.toCharArray();
targetArray = target.name.toCharArray();
if(sourceArray[0] < targetArray[0])
return true;
else
return false;
}
I tested it and it seems to work for my case. Now there's another class called EmployeeList and it manages the employees via an array of employees ("Employee" objects). The size of this array is determined via constructor. My code looks like this:
public class EmployeeList {
/*attributes*/
private int size;
private Employee[] employeeArray;
/* constructor */
public EmployeeList(int size) {
this.employeeArray = new Employee[size];
}
/* methods */
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
/* adds employee to end of the list. Returns false, if list is too small */
boolean add(Employee m) {
int id = m.getID();
if (id > employeeArray.length) {
return false;
} else {
employeeArray[id] = m;
return true;
}
}
/* returns employee at certain position */
Employee get(int index) {
return employeeArray[index];
}
/* Sets employee at certain position. Returns null, if position doesn't exist. Else returns old value. */
Employee set(int index, Employee m) {
if (employeeArray[index] == null) {
return null;
} else {
Employee before = employeeArray[index];
employeeArray[index] = m;
return before;
}
}
Now comes my real problem: In a third class called "employeeManagement" I am supposed to implement the sorting algorithm. The class looks like this:
public class EmployeeManagement {
private EmployeeList ml = new EmployeeList(3);
public boolean addEmployee(Employee e) {
return ml.add(e);
}
public void sortEmployee() {
System.out.println(ml.getSize()); // I wrote this for debugging, exactly here lies my problem
for (int n = ml.getSize(); n > 1; n--) {
for (int i = 0; i < n - 1; i++) {
if (Employee.isSmaller(ml.get(i), ml.get(i + 1)) == false) {
Employee old = ml.set(i, ml.get(i + 1));
ml.set(i+1, old);
}
}
}
}
The "println" before my comment returns "0" in console... I am expecting "3" as this is the size I gave the "EmployeeList" as parameter of the constructor within my "EmployeeManagement" class. Where is my mistake ? And how can I access the size of the object I created in the "EmployeeManagement" class (the "3") ? I'm really looking forward to your answers!
Thanks,
Phreneticus
You are not storing size in your constructor. Something like,
public EmployeeList(int size) {
this.employeeArray = new Employee[size];
this.size = size; // <-- add this.
}
Also, setSize isn't going to automatically copy (and grow) the array. You will need to copy the array, because Java arrays have a fixed length. Finally, you don't really need size here since employeeArray has a length.
The size variable you are calling is the class field. If you take a quick look at your code, the getter is getting the field (which is initialized as zero when created). The size you are using it. The good way of doing it would be to get the size of the array in the getter like this:
public int getSize() {
return employeeArray.length;
}
This would return the size of the array in the object.
I'm completely new and right now I'm writing a bid of code for university. I want to create an open hashtable and I wrote this peace of code:
public class AuDOpenHashTable extends AuDHashTable {
private LinkedList<Contact>[] table;
public AuDOpenHashTable(int capacity) {
super(capacity);
this.table = new LinkedList[capacity];
}
#Override
public void insert(Contact c) {
int position = hash(c.email);
if (table[position] == null) {
table[position] = new LinkedList<>();
}
table[position].add(c);
}
#Override
public void remove(Contact c) throws NoSuchElementException{
int position = hash(c.email);
if(table[position] != null){
table[position].remove();
}
else{
throw new NoSuchElementException();
}
}
#Override
public Contact getContact(String email)throws NoSuchElementException{
int position = hash(email);
table[position].getContact(email);
if(table[position] != null){
return table[position].get(position);
}
else{
throw new NoSuchElementException();
}
}
}
public abstract class AuDHashTable {
protected int capacity;
public AuDHashTable(int capacity){
this.capacity = capacity;
}
public abstract void insert(Contact c);
public abstract void remove(Contact c);
public abstract Contact getContact(String email);
protected int hash(String s){
int hash = 0;
for(int i = 0; i < s.length(); i++){
hash += s.charAt(i);
}
hash = hash % capacity;
return hash;
}
public static void main(String[] args) {
AuDClosedHashTable hashtabelle = new AuDClosedHashTable(3);
Contact eins = new Contact("hans.peter#web.de");
Contact zwei = new Contact("selina.meier#gmail.com");
Contact drei = new Contact("alexander.bauer#gmx.de");
hashtabelle.insert(eins);
hashtabelle.insert(zwei);
hashtabelle.insert(drei);
System.out.println(hashtabelle.isFull());
System.out.println(hashtabelle.getIndexOf("hans.peter#web.de"));
System.out.println(hashtabelle.getIndexOf("selina.meier#gmail.com"));
System.out.println(hashtabelle.getIndexOf("alexander.bauer#gmx.de"));
hashtabelle.remove(drei);
System.out.println(hashtabelle.isFull());
System.out.println(hashtabelle.getContact("selina.meier#gmail.com"));
System.out.println(hashtabelle.getContact("hans.peter#web.de"));
System.out.println(hashtabelle.getContact("alexander.bauer#gmx.de"));
AuDOpenHashTable hashtabelle = new AuDOpenHashTable(3);
Contact eins = new Contact("hans.peter#web.de");
Contact zwei = new Contact("selina.meier#gmail.com");
Contact drei = new Contact("alexander.bauer#gmx.de");
hashtabelle.insert(eins);
hashtabelle.insert(zwei);
hashtabelle.insert(drei);
System.out.println(hashtabelle.getContact("selina.meier#gmail.com"));
hashtabelle.remove(zwei);
System.out.println(hashtabelle.getContact("selina.meier#gmail.com"));
}
}
So, my problem is in the "getContact()" method. If i want to display an account on a certain position and it is the ONLY account on that position, then everything works fine. But, if want to display an account in which the head differs the tail, so there are two accounts, it only give me one account(mostly not the correct one). For these examples the code works very well, but if i decide to pick other names, sometimes it does also not work. But not to make it complicated I wanted to hear your suggestions on how I can improve the "getContact" method. Thanks in prehand.
The hash function will tell you which bucket an item can be in, but you still need to check all the items within the bucket for equality. getContact should iterate over the LinkedList and check the email against each contact, then only return the contact with the matching email. Same for the remove method.
Different keys can have the same hash code. This is detected at insertion usually in which case there's usually a rehash, some algorithm to produce another hash code, that results in another possibly free has code. If not free it is again rehashed. If this continues a lot then the table was possibly allocated to small and a bigger table should be used.
When retrieving the information, you should compare the data at the index with the key searched. If not matching, rehash ( same algorith as insert ) and try again. Until you find it or end up in an empty index, in which case the key was not there.
I have a small bug probably stemming from my misunderstanding of HashMap and it's killing me. I've included a small snippet of test code that illustrates the problem.
I omitted the Prefix class for conciseness, but my prefixes are just arrays of words. They are immutable, so when they are constructed they clone an array of strings passed into the constructor. Hashcode() and equals() methods are implemented so the conditionals pass. Essentially the problem is that I can only dereference the suffix list using prefix1 and not prefix2 (it returns null in the latter case.
FYI, my Hashmap is simply declared as:
// Stores mappings between "prefixes" (consecutive word phrases) and "suffixes" (successor words).
private Map<Prefix, ArrayList<String>> prefixSuffixPairs;
Any help is appreciated.
ArrayList<String> suffixInList = new ArrayList<String>();
suffixInList.add("Suffix1");
suffixInList.add("Suffix2");
String[] prefixWords1 = new String[] {"big", "the"};
Prefix prefix1 = new Prefix(prefixWords1);
String[] prefixWords2 = new String[] {"big", "the"};
Prefix prefix2 = new Prefix(prefixWords2);
prefixSuffixPairs.put(prefix1, suffixInList);
if(prefix1.hashCode() == prefix2.hashCode()) {
System.out.println("HASH CODE MATCH");
}
if(prefix1.equals(prefix2)) {
System.out.println("VALUES MATCH");
}
ArrayList<String> suffixOutList = null;
suffixOutList = prefixSuffixPairs.get(prefix2);
suffixOutList = prefixSuffixPairs.get(prefix1);
public int hashCode() {
int result = 1;
for( int i = 0; i< words.length; i++ )
{
result = result * HASH_PRIME + words[i].hashCode();
}
return result;
}
public boolean equals(Prefix prefix) {
if(prefix.words.length != words.length) {
return false;
}
for(int i = 0; i < words.length; i++) {
if(!prefix.words[i].equals(words[i])) {
return false;
}
}
return true;
}
public boolean equals(Prefix prefix) {
That does not override Object#equals (and thus is not used by the HashMap).
You are merely providing an unrelated method of the same name (overloading) -- but you could call that from the one below:
Try
#Override
public boolean equals(Object prefix) {
The #Override is not strictly necessary, but it would have enabled the compiler to detect this problem if you had applied it to your first method (you get an error when your assertion to override is mistaken).
My problem is this: I have an iterator class which is supposed to iterate through elements in a given data structure, <E> let's say, but what I have managed to accomplish is that when I pass in the data structure it will iterate the data structure itself.
ie. DynamicIterator it = new DynamicIterator(da);
say da is an array the output will be [1,2,3,4,5,6] instead of 1,2,3,4,5,6
My issue is, more than anything, understanding the generally accepted practice for dealing with this more than the issue itself.
edit for code:
public class X<E>
{
private final E[] rray;
private int currentIndex = 0;
public X(E... a)
{
//if the incoming array is null, don't start
if(a == null)
{
System.out.println("Array is null");
System.exit(1);
}
//set the temp array (rray) to the incoming array (a)
this.rray = a;
}
//hasNext element?
public boolean hasNext()
{
return rray.length > currentIndex;
}
//next element (depends on hasNext())
public E next()
{
if (!hasNext())
{
System.out.println("Element doesn't exist, done");
System.exit(1);
}
return rray[currentIndex++];
}
//return array
public E[] access()
{
return rray;
}
}
You won't be able to do this with a completely generic parameter <E> - how would you iterate through a Throwable, for example? What your class X does at the moment is accept any number of objects in its constructor, and then simply returns each of those objects in turn.
If you restricted the bounds of the objects passed in to implement e.g. Iterable, then you can actually start to "look inside" them and return their contents:
public class X<E> {
private final Iterator<E> it;
public X(Iterable<E> a) {
it = a.iterator();
}
public boolean hasNext() {
return it.hasNext();
}
public E next() {
return it.next();
}
}
Although this doesn't really accomplish anything different to just using a.iterator() directly instead of an instance of X...