Remove an Object and add another in TreeSet - java

I am working with Tree Set in java to add some objects in the set . Each object is a signal with different properties. Everytime a new signal comes I set some attributes of the object (Signal) and add it to the set, A signal can come more then one time. For signals I mantain a list in which I store the signal name and when I signal comes I check if the signal is in the list or not If it is not in the list I simply add a new object to my set but if the signal is in the list I take that signal from the set and modify some of its attributes , remove the signal and and add a new one.
The problem is that when I signal comes for the 2nd time or 3rd time and so on it does not remove the old signal and keep all the occurance of the same signal with modified attributes.
Here is my code
SortedSet<Signal> set = new TreeSet<Signal>();
ArrayList< String > messages = new ArrayList< String >();
//If the Message is new one
if(!messages.contains(messageName)){
//System.out.println("I am new signal");
//Add the new Message in Message List
messages.add(messageName);
//Create Object of Message to be stored in Set
signal = new Signal();
signal.setSource(messageSource);
signal.setName(messageName);
if(messageSource.equals("egdci") || messageSource.equals("ugdci"))
signal.setComponent(egdci_ugdci_msgComponent);
else
signal.setComponent(messageComponent);
signal.setOccurance(messageCounter);
signal.setSize(messageContent.length);
signal.setBandwidth(0F);
//Add the new Message Object in the Set
set.add(signal);
}
//If Message already exists in the list
else{
//System.out.println("I am old one");
Iterator<Signal> iterator = set.iterator();
while(iterator.hasNext()) {
signal = (Signal)iterator.next();
if(signal.getName().equalsIgnoreCase(messageName)){
System.out.println("I am here");
int occurance = signal.getOccurance() + 1;
int size = occurance * messageContent.length;
float bandwidth = 0F;
set.remove(signal);
signal = new Signal();
signal.setSource(messageSource);
signal.setName(messageName);
if(messageSource.equals("egdci") || messageSource.equals("ugdci"))
signal.setComponent(egdci_ugdci_msgComponent);
else
signal.setComponent(messageComponent);
signal.setOccurance(occurance);
signal.setSize(size);
signal.setBandwidth(bandwidth);
//Add the new Message Object in the Set
set.add(signal);
}
}
}
writeToCSV(signal , writer);
More over I try to sort my signals in the file on the basis of occurance of a signal, the higher the value of occurance, on the top it should be in the file.
Here is my code of compareTo in Signal.java (I am using Tree Set for the first time so Not sure how to implement my comapreTo)
#Override
public int compareTo(Signal signal) {
int thisOccurance = this.getOccurance();
return thisOccurance.compareTo(signal.getOccurance());
}
Any Help will be highly appreciated...
Thanks in advance

If the problem is only remove the old signal, you can use remove it with:
iterator.remove();
Once the while ends you can create and then add your new Signal to the set.
You else condition should look like:
else {
// System.out.println("I am old one");
final Iterator<Signal> iterator = set.iterator();
boolean deleted = false;
while (iterator.hasNext()) {
signal = (Signal)iterator.next();
if(signal.getName().equalsIgnoreCase(messageName)){
iterator.remove();
deleted = true;
break;
}
}
if(delted){
int occurance = signal.getOccurance() + 1;
int size = occurance * messageContent.length;
float bandwidth = 0F;
signal = new Signal();
signal.setSource(messageSource);
signal.setName(messageName);
if(messageSource.equals("egdci") || messageSource.equals("ugdci"))
signal.setComponent(egdci_ugdci_msgComponent);
else
signal.setComponent(messageComponent);
signal.setOccurance(occurance);
signal.setSize(size);
signal.setBandwidth(bandwidth);
//Add the new Message Object in the Set
set.add(signal);
}
}

Related

java.lang.IllegalStateException in iterator.remove()

Rocket class contains: canCarry(Item item)>checks if this item can be carried/ carry updates the weight with total weight.
U2 class is child of Rocket contains: currentweight, maxWeight=18 tons
Item class contains: name to be shipped & weight.
In the method loadU2 I am trying to access a list of items and adding it into one rocket until maxWeight of that rocket is reached . For example I have 216 tons of items to carry returning a list of 12 ships.
It throws me java.lang.IllegalStateException error in the line iterator.remove(). I do not know how to go about it, but it looks like it is not allowing me to remove the items while iterating.
public ArrayList<Rocket> loadU2(ArrayList<Item> loadItems){
//list of ships
ArrayList<Rocket> U2Ships = new ArrayList<Rocket>();
for(Iterator<Item> iterator = loadItems.iterator(); iterator.hasNext();) {
//create a new ship
Rocket tempShip = new U2();
Item tempItem = iterator.next();
//loop over items check if it can be filled then remove the item that was filled.
while(tempShip.currentWeight<tempShip.weightLimit) {
if(tempShip.canCarry(tempItem)){
tempShip.carry(tempItem);
iterator.remove();
}
}
U2Ships.add(tempShip);
}
return U2Ships;
}
Exception in thread "main" java.lang.IllegalStateException
at java.base/java.util.ArrayList$Itr.remove(ArrayList.java:980)
at Simulation.loadU1(Simulation.java:35)
at Main.main(Main.java:14)
Simplified example of what the code is doing:
Assuming maxWeight for each ship = 11 tons
ArrayList loadItems = [3,5,5,8,1,2,3,5] tons
- Ship[1]=[3,5,1,2]
- new list to iterate over >> [5,8,3,5]
- Ship[2]=[5,3]
- new list to iterate over >> [8,5]
- Ship[3]=[8]
- new list to iterate over >> [5]
- Ship[4]=[5]
Please, rewrite your code by creating new ArrayList, instead of changing the existing list inside its own iterator:
public ArrayList<Rocket> loadU2(ArrayList<Item> loadItems){
//list of ships
ArrayList<Rocket> U2Ships = new ArrayList<Rocket>();
ArrayList<Item> updatedLoadItems = new ArrayList<Item>();
for(Iterator<Item> iterator = loadItems.iterator(); iterator.hasNext();) {
//create a new ship
Rocket tempShip = new U2();
Item tempItem = iterator.next();
//loop over items check if it can be filled then only leave the load item that was not fully filled.
boolean addLoadItem = true;
while(tempShip.currentWeight<tempShip.weightLimit) {
if(tempShip.canCarry(tempItem)){
tempShip.carry(tempItem);
addLoadItem = false;
}
}
if (addLoadItem) {
updatedLoadItems.add(tempItem);
};
U2Ships.add(tempShip);
}
loadItems.removeAll();
loadItems.addAll(updatedLoadItems);
return U2Ships;
}
This is not the best solution, but to provide a better solution, you need to change the signature of public ArrayList<Rocket> loadU2(ArrayList<Item> loadItems)
You can try to improve your code by refactoring it.
Hint: right now your loadU2 method tries to do both things at the same time: change loadItems and create U2Ships. This is a direct violation of the single responsibility principle. Try to imagine the soldier who would try to shoot the gun and throw grenade at the same time! One thing at the time.
The problem is here:
while(tempShip.currentWeight<tempShip.weightLimit) {
if(tempShip.canCarry(tempItem)){
tempShip.carry(tempItem);
iterator.remove();
}
}
You are calling iterator.remove() within a loop. If the condition tempShip.canCarry(tempItem) holds twice, you call iterator.remove() twice, and this is not allowed (the second time, the item is already removed).
I don't know how the method canCarry is implemented, but note that if it is the case that tempShip.currentWeight<tempShip.weightLimit is true, but tempShip.canCarry(tempItem) is false, your loop will run forever.
use listIterator instead of Iterator.
ListIterator<Book> iter = books.listIterator();
while(iter.hasNext()){
if(iter.next().getIsbn().equals(isbn)){
iter.remove();
}
}
like used here.
Remove elements from collection while iterating
public ArrayList<Rocket> loadU2(ArrayList<Item> loadItems){
//list of ships
int shipNum=0;
int itemsloaded=0;
ArrayList<Rocket> U2Ships = new ArrayList<Rocket>();
while(!loadItems.isEmpty()) {
System.out.println("number of ships created: "+shipNum++);
//create a new ship
Rocket tempShip = new U2();
//loop over items check if it can be filled then only leave the load item that was not fully filled.
while(iterator.hasNext()) {
Item tempItem = iterator.next();
if(tempShip.canCarry(tempItem)){
System.out.println("number of items loaded: "+(itemsloaded++));
tempShip.carry(tempItem);
iterator.remove();
}
}
U2Ships.add(tempShip);
}
return U2Ships;
}
Thank you guys for the help, this should fix 2 problems: infinity, and the iterator.remove().

stuck with a malfunctioning while loop

I'm stuck with this problem in home work for a long time now, would appreciate your professional help.
I need to simulate filling up rockets destined for a "mission to Mars" with all kinds of items arranged already in an array list. Maximum weight of each rocket including cargo is a given (18,000 Kg), as well as rocket net weight (10,000 Kg) and each item's weight (Item object includes fields "weight" and "itemType", such as "building material", "water", etc,.)
Instructions are to fill each rocket until it's fully loaded and only then create another one. It seems that my fellow students ignored this instruction so their code cannot help.
Sorting the array in ascending / descending order according to weight does not solve the problem.
My problem is that although I have used while loops all over, rockets refuse to fill up despite still having space left that can be filled with an item still left on the list. Loop won't skip the next 2-3 items (the most I managed to get is skipping one item) and find the one item that can still be loaded.
Bellow is also the list of items.
public ArrayList<U1> loadU1(ArrayList<Item> items) {
ArrayList<U1> fleetU1 = new ArrayList();
int i = 0;
Iterator<Item> iterator = items.iterator();
while (iterator.hasNext()) {
U1 rocketU1 = new U1(); // create new rocket with zero cargo
while (rocketU1.canCarry(items.get(i))) { // "canCarry" checks if item's weight fits in:
/* public final boolean canCarry(Item cargo){
if(currentRocketWeight + cargo.weight <= maxRocketWeight){
return true;
} else {
return false; }} */
rocketU1.carry(items.get(i));
// "carry" updates rocket total weight - no more than 18000 Kg including rocket net weight 10000 Kg, i.e. max cargo weight is 8000 Kg:
/* public final int carry(Item cargo){
currentRocketWeight += cargo.weight;
return currentRocketWeight;}
*/
items.remove(i); // remove loaded item from list
}
fleetU1.add(rocketU1); // add rocket to fleet
}
return fleetU1;
}
/*arraylist "items" - "phase-1.txt":
building tools=2000
building tools=2000
building tools=2000
building tools=5000
building tools=5000
building tools=2000
building tools=1000
building tools=5000
building tools=6000
shelter equipment=5000
construction equipment=5000
plants=1000
steel=8000
books=1000
water=5000*/
public ArrayList<Item> loadItems(int phaseNum) {
try {
switch (phaseNum) {
case 1:
out.println("Loading phase 1:");
fileName = "phase-1.txt";
break;
case 2:
out.println("Loading phase 2:");
fileName = "phase-2.txt";
break;
default:
out.println("argument must be 1 or 2");
}
File file = new File(fileName);
Scanner scanner = new Scanner(file);
while (scanner.hasNextLine()) {
lineFromFile = scanner.nextLine();
String[] list = lineFromFile.split("=");
Item item = new Item(); //(list[0], );
item.itemType = list[0];
item.weight = Integer.parseInt(list[1]);
itemList.add(item); // create ArrayList of items
}
scanner.close();
} catch (Exception ex) {
ex.printStackTrace();
}
return itemList;
}
You need to iterate the items per rocket.
// create a copy of the items so we can remove without harm to the caller
List<Items> ourList = new ArrayList<>(items);
// you should probably sort the list by weight, descending order
while (!ourList.isEmpty()) {
// we need a rocket.
U1 rocket = new U1();
// go through all the items and load if item fits
Iterator<Item> iterator = ourList.iterator();
while (iterator.hasNext()) {
// the next() call that's mentioned in the comment
Item item = iterator.next();
if (rocket.canCarry(item)) {
rocket.carry(item);
// you need to remove from the iterator itself, not from the list
// or you will get an exception because that makes the iterator invalid
// it will remove from the underlying list as well though
iterator.remove();
}
}
fleet.add(rocket);
}
You need to have one method to fill a rocket and then call that method in a loop while there is still cargo left to load. To make this work without recursive calls I have changed the array of rockets, `fleet', to be a class member
private List<Item> loadRocket(List<Item> items) {
Iterator<Item> iterator = items.iterator();
List<Item> loaded = new ArrayList<>();
U1 rocketU1 = new U1();
while (iterator.hasNext()) {
Item item = iterator.next();
if (rocketU1.canCarry(item)) {
rocketU1.carry(item);
loaded.add(item);
}
}
items.removeAll(loaded);
fleetU1.add(rocketU1);
return items;
}
And then call it in a loop
while (!items.isEmpty()) {
items = loadRocket(items);
}
If you don't want to have the ´fleetas a class member you could move the creation of the rocket and adding to thefleetlist to outside of ´loadRocket and instead send it as a parameter.
while (!items.isEmpty()) {
U1 rocket = new U1();
items = loadRocket(rocket, items);
fleet.add(rocket);
}
So here what I would do:
For each item, I would try to place it in a rocket already in the fleet; if not possible, I would add a new rocket to the fleet. If the item cannot fit even in an empty rocket, it is kept in the input list, otherwise, it is removed:
public List<U1> loadU1(List<Item> items) {
List<U1> fleetU1 = new ArrayList<>();
Iterator<Item> iterator = items.iterator();
while (iterator.hasNext()) {
Item item = iterator.next();
U1 rocketU1 = null;
for (U1 u1: fleetU1) {
if (u1.canCarry(item)) {
rocketU1 = u1;
break;
}
}
if (rocketU1 == null) {
rocketU1 = new U1();
if (!rocketU1.canCarry(item)) {
// the item is too heavy
continue;
}
fleetU1.add(rocketU1);
}
rocketU1.carry(item);
iterator.remove();
}
return fleetU1;
}

Iterating through an ArrayList twice when searching for Objects with specified properties

I am trying to iterate through a List, and create a Pair of 2 objects, that are both stored in data. Both objects will have a property isSuspended, one will have the property set to true and other one to false.
This is the code I am using.
Pair<Market, Market> marketPair;
for (Market market : data) {
if (!market.getIsSuspended() && !market.wasProcessed) {
for (Market market2 : data) {
if (market2.getIsSuspended() && !market2.wasProcessed) {
marketPair = new Pair<>(market, market2);
market.setWasProcessed(true);
market2.setWasProcessed(true);
}
}
}
}
However, this code is going to be slow. It is executed on batches with size of 5000. Total number of records is more than 10 millions, so I am searching for a way to make this faster. Do I really need 2 for loops?
Iterate the list once, filtering out wasProcessed. Add entry to one of two lists: isSuspended and notSuspended. Now pair up entries from each list.
List<Market> isSuspended = new ArrayList<>();
List<Market> notSuspended = new ArrayList<>();
for (Market market : data) {
if (! market.wasProcessed) {
if (market.getIsSuspended())
isSuspended.add(market);
else
notSuspended.add(market);
}
}
Iterator iter1 = notSuspended.iterator();
Iterator iter2 = isSuspended.iterator();
while (iter.hasNext() && iter2.hasNext()) {
Market market1 = iter1.next();
Market market2 = iter2.next();
Pair<Market, Market> marketPair = new Pair<>(market1, market2);
market1.setWasProcessed(true);
market2.setWasProcessed(true);
// use marketPair here
}
However, if this is a continual process, processed in batches of 5000, where there might be rollover entries from one of the lists, use a Deque instead.
Deque<Market> isSuspended = new ArrayDeque<>();
Deque<Market> notSuspended = new ArrayDeque<>();
for (;;) { // loop forever
data = /*get next batch here*/;
if (data.isEmpty())
break;
// Find unprocessed
for (Market market : data) {
if (! market.wasProcessed) {
if (market.getIsSuspended())
isSuspended.add(market);
else
notSuspended.add(market);
}
}
// Pair up
while (! notSuspended.isEmpty() && ! isSuspended.isEmpty()) {
Market market1 = notSuspended.remove();
Market market2 = isSuspended.remove();
Pair<Market, Market> marketPair = new Pair<>(market1, market2);
market1.setWasProcessed(true);
market2.setWasProcessed(true);
// use marketPair here
}
}

How to keep adding values to a key that already exists, when the values are in an ArrayList? Input is coming in from a scanner to create a TreeMap

I am trying to receive input from a user where each line must consist of some text (a key), followed by a tab character, followed by a double literal (a value), followed by a newline.
If the user is allowed to keep entering the same key, followed by /t, then a different value and /n, how can I write a program that keeps adding the value to the same key in a tree map?
Each key has an ArrayList, which is where I get stuck because I don't know how to keep adding to an array list for different lines/keys.
This is what I have so far:
TreeMap<String, ArrayList<Double>> categoryMap = new TreeMap<>();
Double val = 0.0;
String inputKey = "";
System.out.println("Welcome, please enter text");
Scanner scn = new Scanner(System.in);
dataSource = scn;
try
{
// adds all words of input to a string array
while (dataSource.hasNextLine())
{
ArrayList<Double> valueMap = new ArrayList<>();
inputKey = dataSource.next();
val = dataSource.nextDouble();
valueMap.add(val);
if (categoryMap.get(inputKey) == null)
{
categoryMap.put(inputKey, valueMap);
}
else
{
categoryMap.put(inputKey, valueMap);
}
dataSource.nextLine();
}
}
// Exception if no lines detected and shows message
catch (IllegalArgumentException lineExcpt)
{
System.out.println("No lines have been input: " + lineExcpt.getMessage());
}
finally
{
scn.close();
}
return categoryMap;
I'm extremely new to java with only about a month of experience.
This is the logic inside your while loop needs some modification. Currently you are overriding the value list with a new one each time.
Here is what you have on paper:
If the key does not exist, create a new list with the given double and use it as the value.
Else, get the (already existing) list and add the double to it.
In code, we just need to modify what you did:
String inputKey = dataSource.next();
double val = dataSource.nextDouble();
List<Double> list = categoryMap.get(inputKey);
if (list == null) // If the key does not exist
{
list = new ArrayList<>(); // create a new list
list.add(val); // with the given double
categoryMap.put(inputKey, list); // and use it as the value
}
else // Else
{
list.add(val) // (got the list already) add the double to it
}
You should get the arraylist for that key from the map and add the value there, something like categoryMap.get (inputKey).add(val) inside your else, code could be improved, but I'm using a phome now...
If you use Java 8, maps have the computeIfAbsent method.
List<Double> addTo = map.computeIfAbsent(key, ArrayList::new);

Compare a list of IDs to a master list, and either create or delete master list records based on found/not found

I have a list of IDs: List<Integer> updatedIds.
I have a master list (say, taken from the DB): List<Records> masterList.
I want to do the following:
For each ID in updatedIds, check if it's in masterList. If not, add the record to the masterList.
For each Record in masterList, check if it's in updatedIds. If not, it is obsolete, so remove it from masterList.
The straightforward code for this is as follows:
for (Integer updId : updatedIds) {
boolean hasMapping = false;
for (Record rec : masterList) {
if (rec.getId() == updId) { hasMapping = true; break; }
}
if (!hasMapping) {
//TODO add updId to masterList
}
}
for (Record rec : masterList) {
boolean isObsolete = true;
for (Integer updId : updatedIds) {
if (rec.getId() == updId) { isObsolete = false; break; }
}
if (isObsolete) {
//TODO remove rec from masterList
}
}
The first loop takes care of requirement 1, the second takes care of requirement 2. It looks very inefficient, and I think I may be using the wrong data structure for this kind of task.
Is there a more efficient way of implementing the algorithm above?
If you sort both lists (e.g. using Collections.sort), the updatedIDs in natural order and the masterList ordered by ID, you can set up a single loop to go through both of them. You could possibly retrieve the records in sorted order, if they come from a DB, and skip that step.
Collections.sort(masterList, myComparator);
Collections.sort(updatedIDs);
Iterator m_it = masterList.iterator();
Iterator u_it = updatedIDs.iterator();
// * Some code here to deal with the possibility that either list is empty
Record rec = m_it.next();
int u = u_it.next();
bool done = false;
while (! done) {
if (rec.getID() < u) {
// rec's ID was missing from updatedIDs
m_it.remove();
if (m_it.hasNext()) {
rec = m_it.next();
} else {
done = true;
// * add u and all subsequent updated IDs to master list
}
} else if (rec.getID() > u) {
// u is new - doesn't occur in masterList
// * add u to masterList (or probably to a separate list that you
// later append to masterList)
if (u_it.hasNext()) {
u = u_it.next();
} else {
done = true;
// * remove rec and all remaining records from the master list
}
} else {
// rec's ID matches u: proceed to next pair of items
bool m_nx = m_it.hasNext(), u_nx = u_it.hasNext();
if (m_nx && u_nx) {
rec = m_it.next();
u = u_it.next();
} else if ((! m_nx) && (! u_nx)) {
done = true;
} else if (m_nx && (! u_nx)) {
done = true;
// * remove all subsequent records from the master list
} else if ((! m_nx) && u_nx) {
done = true;
// * add all subsequent integers in updatedIDs to the master list
}
}
}
use HashSet. that will give you a constant time look up. however, each item in your set should be unique. then you can use that number as hashcode as well and you have O(1) lookup whereas in List you have O(n) lookup time.
You can HashMap<Integer,Records> instead of List<Records>. Where you will get constant look up O(1).
HashMap -> Integer - id and Records - corresponding record.

Categories

Resources