0

I was wondering if I could get some advice please. I have the following code:

 private static int getIndex(String regneeded) {

        System.out.println("The reg passed to getIndex method is:" + regneeded);
         if (arraylist.contains(regneeded)) {
             int pos = arraylist.indexOf(regneeded);
             System.out.println("The position of the vehicle in the array list is:" + pos);
         }else {return -1;}
         return 0;
  }

What I am trying to do is search an Array of DeliveryVehicles, for a specific reg number (that I pass to the method) and then say what position in the ArrayList the object that contains this reg is located.

I know I have an issue as I am searching for a string within an ArrayList and what I have in my ArrayList are objects. So, just looking for any advice while I continue to research.

Thank you in advance. Apologies if this is basic I am very new to Java.

EDIT: To include further information on the objects contained in the ArrayList.

DeliveryVehicle objects are contained in the ArrayList. Each contain registration numbers (they have other attributes but I'm focusing on the registration number to understand this issue first). There are setters (setRegNum()) and getters (getRegNum()) in the base class DeliveryVehicle for the registration number, and I pass the registration number to the constructor when I create my vehicle object as follows:

 DeliveryBike myVehicle = new DeliveryBike("21D789");
        arraylist.add(myVehicle);

I have extended the base class to include a DeliveryBike class (as seen). The code I originally posted was a method in my controller class. So, I suppose I'm confused how to access the registration number within the DeliveryBike object.

Thank you.

NewCoder
  • 85
  • 8
  • What kind of objects do you have in your list? Post that code. You can manually loop through all the elements in a foor loop and compare the part of the object that you're interested in to the parameter, and then return that index. – Vucko May 05 '22 at 07:28
  • Thank you for your reply @Vucko, I will add code to better clarify my question. – NewCoder May 05 '22 at 07:29
  • 2
    Method [contains](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/ArrayList.html#contains(java.lang.Object)) will search for an element in `arraylist` that is a `String` which is identical to `regneeded`. However, I understand that the elements of `arraylist` are instances of `DeliveryVehicle` hence method `getIndex` will always return -1 (minus one). – Abra May 05 '22 at 07:34
  • since your arraylist contains custom objects, you could iterate it using a for loop, and for each object, get the string and compare to regneeded – experiment unit 1998X May 05 '22 at 07:38
  • unless you intend to write custom contains method and override hashcode() and equals() as seen in this link https://stackoverflow.com/a/8322280/16034206 – experiment unit 1998X May 05 '22 at 07:39

4 Answers4

0

You are using the wrong data structure for the problem. Identifying objects with keys such as strings is the perfect use case for a Map. Because strings can be hashed, you can use java.util.HashMap:

import java.util.HashMap;
import java.util.Map;

public class Main
{
    static class DeliveryBike {public String s; public DeliveryBike(String s) {this.s=s;}} 

    public static void main(String[] args)
    {
        Map<String,DeliveryBike> vehicles = new HashMap<>();
        vehicles.put("21D789",new DeliveryBike("21D789"));
        System.out.println(vehicles.get("21D789").s);
    }
}

If you can't change it from being an ArrayList because it is passed in from the outside, put it in a map first and then you can search that map multiple times.

If you do insist on using an ArrayList, because you get it passed from the outside and you will always use it just once, you could also use streams and a filter:

import java.util.ArrayList;
import java.util.List;

public class Main
{
    static class DeliveryBike {public String s; public DeliveryBike(String s) {this.s=s;}} 

    public static void main(String[] args)
    {
        List<DeliveryBike> vehicles = new ArrayList<>();
        vehicles.add(new DeliveryBike("21D789"));
        System.out.println(vehicles.stream().filter(x->x.s=="21D789").findFirst().get().s);
    }

}

Warning

In real world code, you would need to guard against the key not being there in both cases. With the map, vehicles.get() can return null, and with the filter, findFirst() can return an empty optional.

Konrad Höffner
  • 11,100
  • 16
  • 60
  • 118
  • Thank you @Konrad Höffner I unfortunately have to use an ArrayList as part of requirements. I will research if I can somehow use a Map as you suggest. – NewCoder May 05 '22 at 08:11
  • @Nolan22: I expanded the answer. No need to research, Map is part of the standard library and can always be used :-) But if you are dead set against it for some reason, I added an example using streams and a filter. It just won't be as fast when used multiple times. – Konrad Höffner May 05 '22 at 08:15
  • that's great thank you for your help! I will try implement this. – NewCoder May 05 '22 at 08:28
  • Note that you are comparing strings with `==`. You should use `equals`. – MC Emperor May 05 '22 at 08:32
0

You can define generic indexOf method like so:

private static <T,E> int indexOf(List<? extends T> list, BiPredicate<T,E> pred, E e) {
    int i = list.size();
    while (--i >= 0 && !pred.test(list.get(i), e)) {
        // nothing
    }
    return i;
}

You can define the predicate for the reg number:

private static BiPredicate<DeliveryVehicle,String> BY_REGNUMBER
        = (dv,e)->dv.getRegNumber().equals(e);

You would use it as follows:

    list.add(new DeliveryBike("1"));
    list.add(new DeliveryBike("2"));
    list.add(new DeliveryBike("3"));
    list.add(new DeliveryBike("4"));
    list.add(new DeliveryBike("5"));
    System.out.println(indexOf(list, BY_REGNUMBER, "1"));
    System.out.println(indexOf(list, BY_REGNUMBER, "2"));
    System.out.println(indexOf(list, BY_REGNUMBER, "3"));
    System.out.println(indexOf(list, BY_REGNUMBER, "4"));
    System.out.println(indexOf(list, BY_REGNUMBER, "5"));
    System.out.println(indexOf(list, BY_REGNUMBER, "6"));

UPDATE:

An alternative using a function to extract the attribute instead of a predicate:

private static <T,E> int indexOf(List<? extends T> list, Function<T,E> attr, E e) {
    int i = list.size();
    while (--i >= 0 && !attr.apply(list.get(i)).equals(e)) {
        // nothing
    }
    return i;
}

You would you it like this:

    System.out.println(indexOf(list, DeliveryVehicle::getRegNumber, "1"));
    System.out.println(indexOf(list, DeliveryVehicle::getRegNumber, "2"));
    System.out.println(indexOf(list, DeliveryVehicle::getRegNumber, "3"));
    System.out.println(indexOf(list, DeliveryVehicle::getRegNumber, "4"));
    System.out.println(indexOf(list, DeliveryVehicle::getRegNumber, "5"));
    System.out.println(indexOf(list, DeliveryVehicle::getRegNumber, "6"));
Maurice Perry
  • 9,261
  • 2
  • 12
  • 24
0

Well, you would have to walk over the DeliveryVehicles and check whether the registration number of the object is equal to the registration number you're searching:

int getIndex(String search) {
    for (int i = 0; i < arraylist.size(); i++) {
        if (Objects.equals(arraylist.get(i).getRegNum(), search)) {
            System.out.println("The position of the vehicle in the arraylist is: " + i);
            return i;
        }
    }
    return -1;
}

Note that contains and indexOf search for a whole object within a list, but they are not suitable for searching for objects with a specific attribute.

For each object in the arraylist, the attribute registrationNumber is compared to the string you're searching, and if they match, print something to the console and immediately return i, which is the position of the found element.

Otherwise, return -1, which is a sentinel value meaning that there is no object with that registration number.


Note that there are data structures which are a better choice for this kind of scenario, like using a Map or Streams, but I don't think that is in scope of the question.

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
  • thank you for your help, I will try this out and report back. – NewCoder May 05 '22 at 08:31
  • this worked! Thank you! Could I ask, just because I am struggling with the syntax. If I wanted to say delete the object once I located it what would I put in place of the print statement? – NewCoder May 05 '22 at 08:43
  • Well, `ArrayList` has a method [`remove(int index)`](https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/util/ArrayList.html#remove(int)), which removes the object at the specified index. A simple `arraylist.remove(i)` is sufficient. Note that `return i` will then return the position where the now deleted element was once present. – MC Emperor May 05 '22 at 08:50
0

There are differente approaches.

1- You could loop through all elements and compare values

private static int getIndex(String regneeded) {
    for (DeliveryBike vehicle: arrayList) {
        if (vehicle.getRegNumber().equalsIgnoreCase(regneeded)) {
            return arrayList.indexOf(vehicle);
        }
    }

    return -1;
}

2- You could override hashCode and equals methods in your DeliveryBike class

// inside your DeliveryBike class add
@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    DeliveryBike that = (DeliveryBike) o;
    return Objects.equals(regNumber, that.regNumber);
}

@Override
public int hashCode() {
    return Objects.hash(regNumber);
}
private static int getIndex(String regneeded) {
    DeliveryBike searchItem = new DeliveryBike(regneeded);
    return arrayList.indexOf(searchItem);
}

If I'm not mistaken, equals method is used in collections like List, Set and Map in order to know if an element is already included and hashCode method is used by Map collections in order to find the object associated with the key.

In this case you'd only need the equals method but it's common to override both at the same time.


Also I would make two functions for your purpose, one would return the index of the element, the other would display a text using that index. That way you could reuse your code if the project gets bigger!

private static int getIndex(String regneeded) {
    DeliveryBike searchItem = new DeliveryBike(regneeded);
    return arrayList.indexOf(searchItem);
}

private static void showMessage(int index, String regneeded) {
    System.out.println("The position of the vehicle with reg " + regneeded + " in the array list is:" + pos);
}

Hope this helps you!