Im using an array to hold property details stored alphabetically. I know I can't delete any from the array but i want to know how to find a specified property and then move all the other ones down an index and to replace the last one with null so that I don't have a duplicate at the end. My code never seems to come out of the loop.
public void removeProperty(String reference) {
int index;
Boolean found = false;
for (index = 0; index < this.propertyList.length; index++) {
if (this.propertyList[index].getReference().equalsIgnoreCase(reference)) {
this.propertyList[index] = this.propertyList[index + 1];
found = true;
} else {
index++;
}
if (found = true){
while (index < this.propertyList.length) {
this.propertyList[index] = this.propertyList[index + 1];
}
this.propertyList[this.propertyListSize - 1] = null;
this.propertyListSize--;
}
}
}
Here is a solution that makes no use of boolean flag. Other bugs that are resolved include:
1) increase of index inside for loop
2) while loop goes until last item. this will cause ArrayIndexOutOfBounds exceptuion. the loop should go until item before last.
public void removeProperty(String reference) {
int index;
// loop until reference found or end of array
for (index = 0;
index < this.propertyList.length &&
this.propertyList[index].getReference().equalsIgnoreCase(reference) == false;
index++);
// if we didnt reach end of array - then we found refernce
if (index < this.propertyList.length) {
// loop until item before last
while (index < this.propertyList.length-1) {
this.propertyList[index] = this.propertyList[index + 1];
index++;
}
// nullify last item
this.propertyList[this.propertyList.length-1] = null;
this.propertyListSize--;
}
}
I know this doesn't answer most of your question but you can use apache commons ArrayUtils to remove an item from the array. Here's the link.
Related
I'm trying to remove an element from an array. I am running into an issue where when I run my program and remove a certain index. I get nulls in the place where the element/index should be removed entirely.
My output is when I execute list.display() in the main method is
Tom, Bob, Richard
However after I execute list.remove() and run the program. I get
null, null, Richard.
Any tips?
public class MyArrayList implements MyList {
private Object[] theList;
public MyArrayList()
{
theList = new Object[0];
}
public boolean add(Object toAdd){
if(toAdd != null) {
Object[] temp = new Object[theList.length + 1];
for(int i = 0; i < theList.length; i++) {
temp[i] = theList[i];
}
temp[theList.length] = toAdd;
theList = temp;
return true;
} else {
return false;
}
}
public Object remove(int index) {
if (index >= 0 && index < theList.length) {
Object[] temp = new Object[theList.length - 1];
theList[index] = null;
int j = 0;
for (int i = 0; i < theList.length; i++) {
if (i == index) {
continue;
}
temp[j++] = theList[i];
theList = temp;
}
return temp;
}
return null;
}
public class Main {
public static void main(String[] args) {
MyArrayList list = new MyArrayList();
list.add("Tom");
list.add("Bob");
list.add("Richard");
list.display();
list.remove(0);
list.remove(1);
list.display();
}
}
Where you call list.remove(0), you should be assigning the result back to list again. For example:
list = list.remove(0);
A couple of other things:
It's generally a bad idea to change the index variable within a loop. It's legal, but leads to logic errors that can be difficult to reason about and diagnose.
You're getting the null in your output because the remove method also mutates the theList when you execute:
theList[index] = null;
Since you're returning a copy of theList you don't need to also set that element of the theList array to null.
Since your code implements MyList which is not available in code, i could not run below sample on your code but you can have below logic in your code. You don't need extra temp array in remove method. Since it an array, you can start traversing array from index which has to be removed and start moving next element by one step before.
public Object remove(int index) {
if (theList == null || index < 0 || index >= theList.length) {
return theList;
}
for (int i = index; i < theList.length; i++) {
theList[i] = theList[i + 1];
}
return null;
}
You can trim array tail if it has more empty places based on some threshold.
the code is doing exactly what you asked it to do. Those removed values are null because you have this line
theList[index] = null;
Also think about what your intentions are.
list.remove(0); <- this will remove the first element so now list would be Rob, Richard
list.remove(1); <- this will remove the 2nd element of the modified list (Rob, Richard) so result would be Rob. This is probably not what you want.
instead of this
if (i == index) {
i++; // risk of out of bounds exception
}
you probably want this instead
if (i == index) {
continue;
}
I need to make my own data structures and part of this is doing an ArrayList. I need to make sure I can add an object at element n while pushing all the others down. Here is my code. Right now it is adding the element twice. It is the function public ReturnObject add(int index, Object item). I need this function to add the object at the specified index and then shift the others down.
public class ArrayList implements List{
public static final int CAPACITY=16;
private int size = 0;
private Object[] data;
ReturnObjectImpl ro;
//constructors
public ArrayList() {
data = new Object[CAPACITY];
} //CONSTRUCTS LIST WITH DEFAULT CAPACITY
public ArrayList(int capacity) { // constructs list with given capacity
data = new Object[capacity];
System.out.println("Created an ArrayList of capacity " + capacity);
}
public boolean isEmpty(){
if(size == 0) {
// System.out.println("The list is empty");
return true;
}
return false;
}
public int size(){
System.out.println("The ArrayList is not full, but currently has " + size + " indexs");
return size;
}
public ReturnObject get(int index){
ro = new ReturnObjectImpl(data[index]);
return ro;
}
public ReturnObject remove(int index){
return null;
}
public ReturnObject add(int index, Object item){
if(index <= size && index < data.length){
for (int x = size-1; x >= index; x--){
data[x+1] = data[x];
data[index] = item;
ro = new ReturnObjectImpl(data[index]);
size++;
}
System.out.println("Added to array at " + index);
}
return ro;
}
public ReturnObject add(Object item){
if (data[0] == null){
data[0] = item;
}
//int adding = size + 1;
data[size] = item;
System.out.println("Added item to index " + size);
size++;
return null;
}
//added - but DELETE BEFORE SUBMITTING
public void printAll(){
for(int x = 0; x < data.length; x++){
System.out.println(data[x]);
}
}
}
Obviously, when inserting an object into that array:
for (int x = size-1; x >= index; x--){
data[x+1] = data[x];
data[index] = item;
that should not happen within a loop! Insertion should happen exactly once, at the correct index! So even when you keep that loop to move the other elements, that last assignment should go after that "moving loop" is over.
So the point is: you should step back and carefully look what this loop is doing with its loop variable.
In other words: either take a piece of paper and "run" the code yourself; or run it in a debugger.
As this is probably some kind of homework activity, I will leave it with that; it should be really enough to get you going and help you fix your code.
In addition to GhostCat's answer, instead of a for loop, you can just use System.arrayCopy() to 'move' the right part to the right. You only need to know whether your internal array (data) is already full or not. If it is, then you must expand the internal array.
System.arraycopy(this.data, insertIndex, this.data, insertIndex + 1, 1);
Some notes:
The code
if (data[0] == null) {
data[0] = item;
}
will throw an ArrayIndexOutOfBoundsException if ArrayList(0) was called.
The code
if (size == 0) {
// System.out.println("The list is empty");
return true;
}
return false;
can be rewritten to
return (size == 0);
You seem to omit more checks, like the check whether the internal array is full or not. Your current code does not expand the internal array, so if one ever adds more objects than the initial capacity (default 16), then an ArrayIndexOutOfBoundsException is thrown.
I am trying to create a method that sets every instance of the variable elt in an array to null, and then shift every variable after it to the left. The current code that I have written only sets the first instance of the variable to null and shifts all other variable to the left, but does not set any other instance of elt to null. The code I have so far is below.
public T remove(T elt) {
boolean exist = false;
for (int i=0; i<data.length; i++) {
if (data[i] == elt) {
data[i] = null;
size--;
exist = true;
for (++i; i < data.length; i++) {
data[i-1] = data[i];
}
}
}
if (exist == true)
return elt;
else
return null;
}
In main, I have the following code:
public static void main(String[] args) {
Bag<String> sbag = new Bag<String>();
sbag.add("Noriko");
sbag.add("hello");
sbag.add("Buddy");
sbag.add("Mary");
sbag.add("Peter");
sbag.add("hello");
sbag.remove("hello");
When I print the array, I expect the following output:
Noriko
Buddy
Mary
Peter
Instead I get:
Noriko
Buddy
Mary
Peter
hello
This tells me it is only setting the first instance of elt to null, moving every variable to the left, and stopping. Can anyone tell me how I can fix my code so that it sets every instance of the variable elt null?
The common technique to the "remove all and shift" problem is to do it all in one loop with two separate indexes - one for reading, and one for writing:
int rd = 0, wr = 0;
while (rd != data.length) {
if (data[rd] != elt) { // Shouldn't you use equals() instead?
data[wr++] = data[rd++];
} else {
rd++;
}
}
while (wr != data.length) {
data[wr++] = null;
}
This technique is very useful in practice. I highly recommend working through an example or two with paper and pencil to make sure that you fully understand it.
Both your innner and outer loop use the variable i. When the first match is found, the record is removed and i is incremented to data.length (when shifting the remaining records to the left). When you get back to the outer loop, i = data.length and the outer loop terminates.
You should use a different variable for your inner loop.
From the looks of your code it would seem like you would want to use a "List" type.
With this you can then add and remove variables without having to write an entire new function to do it.
For the sake of excercise:
public T remove(T elt) {
boolean exist = false;
for (int i=0; i<size; i++) { // changed data.length to size to avoid unnecessary iterations over deleted positions
while (data[i] == elt) { // changed if to while
data[i] = null;
size--;
exist = true;
for (int j = i+1; j < data.length; j++) { // changed iteration variable, we don't want to move i
data[j-1] = data[j];
}
}
}
if (exist == true)
return elt;
else
return null;
}
public static boolean isComponentBefore(GuiInterface component) {
int index = 0;
for (int i = 0; i < components.size(); i++) {
if (components.get(i).getName() == component.getName()) {
if(components.get(i- 1) == null){
return false;
}
}
}
return true;
}
I currently use this, though this can lead to ConcurrentModificationExceptions & it isn't working because it keeps throwing ConcurrentModificationExceptions whenever I try to see if the element before the element passed in is null.
I was wondering if there are other ways to do this.
Looking at your logic, you will a NullPointerException incase the component in the ArrayList before the given component is null, because components.get(i) would be null and components.get(i).getName() will throw the NPE.
You can try to change the logic here a bit. For every null element in the list, check if the next component is the component you're searching for and return accordingly.
for (int i = 0; i < components.size(); i++) {
if (components.get(i) == null) { // If a particular element is null, check if the next element is what you want
if(components.get(i+1).getName().equals(component.getName())) { // you need to handle the edge case for i+1 as well for the last iteration
return false;
}
}
}
Note that you need to compare the Strings using equals() method and not the == operator. You also need to handle the corner case of i+1 for the last iteration.
This line
if (components.get(i).getName() == component.getName()) {
Should be
if (components.get(i).getName().equals(component.getName())) {
However, your condition can never happen. If component.get(i-1) is null, then in the previous loop iteration
components.get(i).getName() // <-- null pointer exception, so
component.get(i-1) must not be null and you need to hope that i isn't 0 or you'd get an index out of bounds exception.
Use an iterator
e.g
int i = 0;
Iterator<GuiInterface > it = components.iterator();
while (it.hasNext()) {
i++;
GuiInterface thisComp = it.next ();
if (thisComp.getName().equals(component.getName())) {
if(i > 0 && components.get(i- 1) == null){ // this code does not make sense
return false;
}
}
}
Assuming the passed component is not in your list:
public static boolean isComponentBefore(GUIComponent component) {
// Start at 1 to avoid IndexOutOfBounds
for(int i = 1; i < components.size(); i++) {
if (components.get(i).getName().equals(component.getName())) {
return components.get(i - 1) != null;
}
}
// Given component is not in the list, or the list only has one element
return false;
}
Assuming the passed component is in the list:
public static boolean isComponentBefore(GUIComponent component) {
int index = components.indexOf(component);
return index > 0 && components.get(index - 1) != null;
}
I'm currently writing a parser for a language that I'm creating, which needs to check if the current part of the stream fits one of the items in the passed array. A short version of the code is:
public abstract class Parser {
private StringReader reader; //This is a BufferedReader with rollback
//A single string lookahead method
public boolean lookahead(String toMatch, boolean rollback) throws ParseException {
char c;
//Mark the current position in the stream, so we can come back to it if needed
MarkToken currentMark = reader.mark();
//Iterate through the toMatch and check if each character matches
for(int i = 0; i < toMatch.length(); ++i) {
c = reader.nextChar();
if(toMatch.charAt(i) != c) {
break;
}
}
//Get the current image
String got = reader.currentImage(currentMark);
//If we don't have a match, rollback if necessary and return false
if(!got.equals(toMatch)) {
if(rollback) {
reader.rollBack();
}
return false;
}
return true;
}
//The String[] lookahead method
public int lookahead(String[] toMatch, boolean rollback) throws ParseException {
if(toMatch.length == 1) {
//If there is only one element in toMatch, send it to a cheaper function
if(lookahead(toMatch[0]))
return 0;
else return 1;
} else {
int maxLength = toMatch[0].length();
//We use this variable to keep track of how many valid choices are left
int choicesLeft = toMatch.length;
int i, j;
char current;
//Mark the current position in the stream, so we can come back to it if needed
MarkToken mark = s().mark();
//Get the length of the longest string in toMatch
for(i = 1; i < toMatch.length; ++i) {
maxLength = Math.max(maxLength, toMatch[i].length());
}
//Go up to the length of the longest string
for(i = 0; i < maxLength; ++i) {
//Get the next character from the stream
current = reader.nextChar();
//If we've reached the end of the stream:
if(current == -1 || current == '\uffff') {
//Get back a character in the stream
reader.rollbackChar();
//And check to see if we have a match
return ArrayUtils.indexOf(toMatch, reader.currentImage(mark));
}
//Go through each item in toMatch
for(j = 0; j < toMatch.length; ++j) {
if(toMatch[j] != null) {
//Check to see if the character matches or not
if(toMatch[j].charAt(i) != current) {
//We null an item in toMatch if it doesn't apply any more
toMatch[j] = null;
--choicesLeft;
}
}
}
//If we only have one choice left, see if there is a match (will return -1 if not)
if(choicesLeft == 1) {
return ArrayUtils.indexOf(toMatch, reader.currentImage(mark));
}
}
//If there is no
if(rollback) {
reader.rollBackTo(mark);
}
}
return -1;
}
}
This function would be called to check if the stream contained certain symbols (. .* $# // " ' """ ''' etc.) and consume them greedily.
I would only be providing an array of maximum 10-15 items at once, so removing items from the array may not be the best optimisation.
Is there a more efficient way of doing this, certain methods or loops that I should be using?