Removing from an Array without holes - java

I have an Array of Cars that contains Car objects and I've been stuck for a while now on the method that gets a car number and needs to delete all objects that has that car number and then return that array without any holes. it's my homework so I can't use any arrayList or Array. methods.
I've tried to do the following but for some reason when I try to run it, it doesn't complie and gives me a IndexOutOfBounds error and refer me to my toString method(it prints all of the cells in the array).
noOfCars, saves the amount of cars there actually is right now as we built the array with a container constructor for holding more places for future cars just in case.
public void removeCarNumbers(int CarNum) {
int count = 0;
for(int i = 0; i < this.noOfCars; i++) {
if(this.cars[i].getCarNum() == CarNum) {
this.cars[i] = this.cars[noOfCars- 1 - count];
count++;
}
}
CarsLines [] newArr = new CarLines[this.noOfCars- count];
for(int i = 0; i< this.noOfCars - count; i++)
{
newArr[i] = this.cars[i];
}
this.cars= newArr;
}
*edit: after playing with it more I still get an error that refers me to my toString() method. is there a problem with it as well?
public String toString()
{
String output = "";
for (int i = 0; i < this.noOfCars; i++)
output += "" + this.cars[i].toString() + "\n";
return output;
}

Try:
// count
int count = 0;
for(int i = 0 ; i < this.cars.length ; ++i) {
if(this.cars[i].getCarNum() == CarNum) {
++count;
}
}
// create new array
CarsLines[] newArr = new CarLines[this.cars.length - count];
int index = 0;
for(int i = 0 ; i < this.cars.length ; ++i) {
if(this.cars[i].getCarNum() != CarNum) {
newArr[index++] = this.cars[i];
}
}
// assign
this.cars = newArr;

I don't think those two loops are doing what you think they are. In the first loop you should eliminate Cars which have the same number, perhaps setting them to null:
for (int i = 0; i < this.cars.length; i++) {
if (this.cars[i] != null && this.cars[i].getCarNum() == CarNum) {
this.cars[i] == null;
} else {
count++;
}
}
This will now eliminate duplicates, and keep a count of unique Cars. In the second loop, fill in just the non-null values:
CarsLines [] newArr= new CarLines[count];
int index = 0;
for(int i = 0; i< this.cars,length; i++)
{
if (this.cars[i] != null) { // Only pass in the non-null values
newArr[index] = this.cars[i];
index++;
}
}
this.cars= newArr;
Before you had this creating pretty much an identical copy of your list because you were filling it in on a one-to-one basis i.e. the same index.
Another possible way of doing this would be an in place conversion:
for (int i = 0; i < this.cars.length; i++) {
if (this.cars[i] != null && this.cars[i].getCarNum() == CarNum) {
for (int j = i+1; j < this.cars.length; j++) { // This loop will shift the
this.cars[j-1] = this.cars[j]; // whole list down one when
} // a duplicate is found,
// overwriting it.
i--; // sets the index back to recheck the shifted list.
this.noOfCars--; // You removed one duplicate by overwriting it
}
}
In response to #Boris The Spiders Comment, you could reduce the complexity of this algorithm by eliminating the inner for loop. I would recommend doing this by tracking the last valid position and using that for updating.
int writeIndex = 0;
for (int readIndex = 0; readIndex < this.cars.length; readIndex++) {
if (this.cars[readIndex] != null && this.cars[readIndex].getCarNum() == CarNum) {
// pass on this because nextIndex should track only the valid cars.
} else {
this.cars[writeIndex++] = this.cars[readIndex];
}
if (writeIndex < readIndex) {
this.cars[i] = null;
}
}
The idea is that you keep one index for reading (i) and one index for writing writeIndex. If your readIndex gets ahead of your writeIndex (this means you found a duplicate) you should clear it after it is read, and you will transer if to the previous writeIndex.
EDIT In response to the addition to your question, you should be extra careful on how noOfCars is calculated as this is probably the source of your Exception, instead try a more reliable indexing method by using the intrinsic length property from your array:
public String toString() {
String output = "";
for (int i = 0; i < this.cars.length; i++) {
if (this.cars[i] != null) {
output += "" + this.cars[i].toString() + "\n";
} else {
// condition that the i-th car is null
output += "null\n"; // one possible approach
// you could also do nothing and your toString would output just the non-null cars
}
}
return output;
}
for reliability, at the cost of efficiency, you could implement a count() method to double check your tracking. Maybe as a temporary check until your sure it is working correctly.
public int getNumCars() {
int c = 0;
for (int i = 0; i < this.cars.length; i++) {
if (this.cars[i] != null) {
c++;
}
}
return c;
}

For every car that you remove try swapping the last element in the array into the "hole". Keepa counter for the max element that is valid and decrement it everytime you swap out an element into the hold. You are basically rearragning the array elemtns in place
int max=this.noOfCars.length;
int i=0;
do{
if(this.cars[i]==null)
break;
if(this.cars[i].getCarNum() == CarNum) {
this.cars[i] = this.cars[max-1];
this.cars[max-1] = null;
}
else{
i++;
}
}while(1==1);
PS: you might have to add a few checks for boundary conditions(like empty array)

Here is a simple example of how to do this with a single loop, no nested loops.
The idea is that you keep track of how maybe elements you have removed (also how many null elements you have found) and then, if the current element is not to be removed, just shift it back by that number.
public static void main(final String[] args) throws IOException {
final Integer[] data = {1, 2, 2, 3, 4, 5, 1, 2, 3, 7, 8, 2, null, null, null};
int shift = 0;
for (int i = 0; i < data.length; ++i) {
if (data[i] == null || data[i] == 2) {
shift++;
data[i] = null;
} else if (shift > 0) {
data[i - shift] = data[i];
data[i] = null;
}
}
System.out.println(Arrays.toString(data));
}
Output:
[1, 3, 4, 5, 1, 3, 7, 8, null, null, null, null, null, null, null]
So you can see the 2s have been removed and the rest have been shifted up.

Related

How do I return an array of object references with a specific length?

I have an array of object references with a size of 100. The array is filled with 4 object references while the rest of it is empty. What I want to do is return the array with only those 4 references. I tried creating a new array and copying the references into it, but then I always get an error saying the array is null when I try to invoke the method. Here's the code:
public Robots[] getRobots() {
for(int i = 0; i < robots.length; i++) {
if(robots[i] != null)
count++;
}
Robots[] newRobots = new Robots[count];
newRobots = Arrays.copyOfRange(robots, 0, count);
return newRobots;
}
I suppose you need to fix 2 errors:
clear the count variable
don't assume that all not null objects are at the beginning
here is the fixed code:
public Robots[] getRobots() {
int count = 0;
for(int i = 0; i < robots.length; i++) {
if(robots[i] != null)
count++;
}
Robots[] newRobots = new Robots[count];
count = 0;
for(int i = 0; i < robots.length; i++) {
if(robots[i] != null)
newRobots[count++] = robots[i];
}
return newRobots;
}

How do I remove duplicated strings in an array of strings?

public static String[] dictionary(String s){
int count=0;
String[] ans = sentence(s);
int size = ans.length;
for (int i = 0; i < size - 1; i++) {
for (int j = i + 1; j < ans.length; j++) {
if (ans[i].compareTo(ans[j]) > 0) {
String temp = ans[i];
ans[i] = ans[j];
ans[j] = temp;
}
}
}
for (int i = 0; i < ans.length; i++) {
ans[i] = [i].to lowerCase);
}
return ans;
}
I have to find duplicated strings and remove them from an array of strings that are sorted lexicographically
Because you know that incoming array sorted, you can get current element and compare next elements with current one. If it is equals skip it, otherwise add this element to the result, and change current. Something like this
public static String[] dictionary(String s){
String[] ans = sentence(s);
if (ans == null || ans.length == 0) {
return ans;
}
List<String> result = new ArrayList<String>();
String current = ans[0];
result.add(current);
for (int i= 1; i < ans.length; i++) {
if (!ans[i].equals(current)) {
result.add(ans[i]);
current = ans[i];
}
}
return result.toArray(new String[0]);
}
If you don't want to use sets, you can do it like this. And it does not require a sorted array. It works as follows. Note: This changes the passed in array.
Get the first element. If it is null continue to next element.
Compare first element to next.
If equal, replace next with a null and increment removed
Continue processing elements.
Now create a new array of original size minus - removed.
And copy all non null values to new array and return it.
public static String[] removeDups(String[] arr) {
// keep track of removed values
int removed = 0;
for (int i = 0; i < arr.length-1; i++) {
for (int j = i+1; j < arr.length; j++) {
if (arr[i] == null) {
// skip this entry and go to next
break;
}
if (arr[i].equals(arr[j])) {
// designate as removed
arr[j] = null;
removed++;
}
}
}
// copy remaining items to new array and return.
String[] result = new String[arr.length-removed];
int k = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] != null) {
result[k++] = arr[i];
}
}
return result;
}
If you want to do it with streams you can do it this way.
String[] result = Arrays.stream(arr).distinct().toArray(String[]::new);
A simple way to do this would be to place them into a set
Set<String> setsHaveNoDuplicates = new HashSet<>(Arrays.asList(ans));
Sets have no duplicates, and if you want to convert the set back to an array of strings, you can do this
String[] result = setsHaveNoDuplicates.toArray(new String[0]);

Reduce the length of a list for the next iteration

I'm trying to reduce the length of the List up to the indexes which were modified while traversal. However, I'm trying to avoid using another list in order save space. Is it possible to :
make this change.
Override a final function lists.length
public ListNode mergeKLists(ListNode[] lists) {
int amount = 0;
while(amount != 1){
amount = 0;
if(lists.length%2 == 0){
for (int i = 0; i < lists.length; i++){
lists[amount] = merge2lists(lists[i] , lists[i + 1]);
amount++;
i++;
}
lists.subList( 0 , amount - 1); //will not work
lists.length = amount; // will not work
}
}
}
I solved this problem using another variable which keeps the record of length.
public ListNode mergeKLists(ListNode[] lists) {
int amount = 0;
int length = lists.length;
while(amount!= 1){
amount = 0;
if(lists.length%2 == 0){
for (int i=0; i<length; i++){
lists[amount] = merge2lists(lists[i] , lists[i+1]);
amount++;
i++;
}
length = amount;
}
else{.....}
}

Java- Manually sort a string array using compareTo() method

Let me first say that I know that there a better ways to sort where you might use something other than an array. This an assignment for class where the user can store strings in an array, delete, display, and sort them. I am completely lost to where to go from here. I am trying to use a bubble sort and everything works except whatever is the first entry in my array won't sort. I avoid null pointer exceptions through filtering out null values which is why my if statement is so long.
private void sortItems(String[] cargohold) {
String temp;
for (int i = 0; i < cargohold.length - 1; i++) {
for (int j = 1; j < cargohold.length; j++) {
if (cargohold[i] != null && cargohold[j] != null && (cargohold[i].compareTo(cargohold[j]) < 0)) {
temp = cargohold[j];
cargohold[j] = cargohold[i];
cargohold[i] = temp;
}
}
}
}
I have tried a bunch of different ways of doing this and I can't find any good reason why this shouldn't work. I have looked through anything I could find on Stack Overflow as far as examples and no one is having the same issue I am.
To recap, I may have 5 strings, "Derp", "Herp", "Sam", "Alfred", "Bill" and this sort will give me: "Derp", "Alfred", "Bill", "Herp", "Sam". Thanks in advance for the guidance.
The line
if(cargohold[i] != null && cargohold[j] != null && (cargohold[i].compareTo(cargohold[j]) < 0))
should be
if(cargohold[j] != null && cargohold[j-1] != null && (cargohold[j].compareTo(cargohold[j-1]) < 0))
and the swapping should be done as:
temp = cargohold[j];
cargohold[j] = cargohold[j-1];
cargohold[j-1] = temp;
Remember that in bubblesort you compare adjacent elements, where as your code does not do that.
Flaw
There will be cases when i > j and i < j, but the swapping logic remains the same, and that is completely wrong.
Bubblesort algorithm with some optimizations:
private static void sortItems(String cargohold[]) {
String temp;
boolean wasSwap = true;
for (int index1 = 0; index1 < cargohold.length - 1 && wasSwap; ++index1) {
wasSwap = false;
for (int index2 = 0; index2 < cargohold.length - index1 - 1; ++index2) {
if (cargohold[index2].compareToIgnoreCase(cargohold[index2+1]) > 0) {
temp = cargohold[index2];
cargohold[index2] = cargohold[index2+1];
cargohold[index2+1] = temp;
wasSwap = true;
}
}
}
}
Average complexity being O(n^2) with the best case of O(n).
Your implementation is wrong.
Here is bubble sort (in a java-like shorthand):
for (index1 = 0; index1 < array.length - 1; ++index1)
for (index2 = index1 + 1; index2 < array.length; ++index2)
if (array[index1] < array[index1])
swap(array[index1], array[index2]);
note the index2 = index1 + 1 of the inner loop.
String[] str = { "red", "blue", "green" };
int n = str.length;
String temp;
System.out.println("Original String Array = " + Arrays.toString(str));
for(int a=0;a<n;a++) {
for(int b=a+1;b<n;b++) {
if( str[a].compareTo(str[b]) > 0 ) {
temp = str[a];
str[a] = str[b];
str[b] = temp;
}
}
}
System.out.println("Sorted String Array = " + Arrays.toString(str));

Exception:java.lang.NullPointerException when comparing two strings of two different string arrays

I'm coding trough codingbat.com/java and ran into an error i don't understand. I got two String arrays and want to compare them. If I just use the arrays all works fine (but the result is not right). To get the right result I programmed a helper function which eliminates all duplicates of an array. I tested the helper function, it returns the array shortened of the duplicates.
I can retrieve the values in the new Arrays with _a[i] etc., and don't get errors, but if i use _a[0].equals(_b[0]) or _a[0].compareTo(_b[0]) I get a NullPointerException (_a[0] == _b[0] works fine...).
If I just use the original arrays a,b the code runs without problems. I don't comprehend why i get a NullpointerException there.
Thanks for any help!
Code:
public int commonTwo(String[] a, String[] b) {
String[] _a = killDuplicate(a);
String[] _b = killDuplicate(b);
int ai=0, bi=0,count=0;
for (int i = 0; ai < _a.length & bi < _b.length; i++){
if ( _a[ai].compareTo(_b[bi]) > 0) { //NullPointerException here, but not if I use a,b
bi++;
} else if ( _a[ai].compareTo(_b[bi]) < 0){ //NullPointerException here, but not if I use a,b
ai++;
} else {
count++;
ai++;
bi++;
}
}
return count;
}
Helper Function:
public String[] killDuplicate(String[] a){
String temp = "";
int counter = 0, counter2 = 0;
for (int i = 0; i < a.length; i++){
if (! a[i].equals(temp)){
temp = a[i];
} else {
a[i] = "";
counter++;
}
}
String[] result = new String[a.length - counter];
for (int i = 0; counter2 < counter; i++){
if (a[i].equals("")) {
counter2++;
}
} else {
result[i-counter2] = a[i];
}
return result;
}
I guess you assume that your array of strings is sorted, otherwise your killDuplicate method wouldn't make sense at all.
The problem with your code is that in the second for loop in killDuplicate method you iterate with condition counter2 < counter which says iterate until all found duplicates are passed. So when you find your last duplicate you exit without filling the rest of the array. Try with example: new String[]{"A", "A", "B", "C"} you'll get [A, null, null].
There are numerous things that can be improved but the simplest modification of your code below. (I've changed only the second for loop)
public String[] killDuplicate(String[] a) {
String temp = "";
int counter = 0, counter2 = 0;
for (int i = 0; i < a.length; i++) {
if (!a[i].equals(temp))
temp = a[i];
else {
a[i] = "";
counter++;
}
}
String[] result = new String[a.length - counter];
for (int i = 0; i < a.length; i++) {
if (a[i].equals("")) continue;
result[counter2] = a[i];
counter2++;
}
return result;
}

Categories

Resources