Home > Blockchain >  Accessing elements of object in ArrayList
Accessing elements of object in ArrayList

Time:05-05

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.

CodePudding user response:

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.

CodePudding user response:

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.

CodePudding user response:

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!

CodePudding user response:

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"));
  • Related