ghosts
ghosts

Reputation: 51

ArrayList of Possibly Many ArrayLists

I want to be able to achieve some sort of class or variable that can store possibly many ArrayLists inside using Java.

For example, a two dimensional ArrayList would be like this: ArrayList<ArrayList<Data_type>>.

A three dimensional ArrayList is like this ArrayList<ArrayList<ArrayList<Data_type>>>.

And so on for any N sized ArrayList.

I want to implement a function that can take any N sized arraylist as a parameter, and I'm not quite so sure how to implement this and how the function signature would look like. I'm currently trying to use Generics which I have used in the past, but in this situation I'm a little lost.

Any suggestions?

Upvotes: 2

Views: 83

Answers (3)

daysling
daysling

Reputation: 118

In this time, You can create a loop and a recursion while checking if the object obtained is a ArrayList, if it is a arrayList do a recursion again.. Here is a example

// Suppose I've a ArrayList<ArrayList<ArrayList<String>>>


/**
* @param ArrayList<?>
* Prints out all the values inside all the ArrayList present in the ArrayList
*/
public static void printArrayItems(ArrayList<?> a) {
    a.forEach((e) -> {
         if(e instanceof ArrayList) printArrayItems((ArrayList) e); else System.out.println(e);
    });
}

Upvotes: 1

MC Emperor
MC Emperor

Reputation: 22997

One way would be to create a Container class with either a wrapped value or a list with values:

class Container<T> {
    private boolean isSingleElement;
    private T value;
    private List<Container<T>> list;
}

You could then add these constructors and static factory methods. They are able to create the containers.

private Container(T value) {
    this.value = value;
    this.isSingleElement = true;
}

private Container(List<Container<T>> values) {
    this.list = Collections.unmodifiableList(values);
    this.isSingleElement = false;
}

public static <T> Container<T> ofSingle(T value) {
    return new Container<>(value);
}

public static <T> Container<T> ofList(List<T> list) {
    return new Container<>(list.stream()
        .map(Container::new)
        .toList());
}

You could then add methods to retrieve the information of what's in the container:

public boolean isSingleElement() {
    return isSingleElement;
}

public T value() {
    if (!isSingleElement) {
        throw new IllegalArgumentException();
    }
    return value;
}

public List<Container<T>> list() {
    if (isSingleElement) {
        throw new IllegalArgumentException();
    }
    return list;
}

Note that the list() and value() methods both throw an IllegalArgumentException if the container contains a single element or a list respectively. The disadvantage of this is that this causes to throw an error at runtime if the wrong method is called.

You could also remove the value() method altogether, and wrap a single element into a list, if you wish:

public List<Container<T>> list() {
    if (isSingleElement) {
        return List.of(new Container<>(value));
    }
    else {
        return list;
    }
}

Upvotes: 2

GeertPt
GeertPt

Reputation: 17854

Generics was added to have better type-safe code. But if you don't know the dimension, you can't create a type-safe N-dimensional structure using nested ArrayLists.

Perhaps you could use a flattened structure mapping coordinates to values.

Map<List<Integer>, DataType> twoDimensionalMap = Map.of(
    List.of(0,0), value00,
    List.of(0,1), value01,
    List.of(1,0), value10,
    List.of(1,1), value11
)
Map<List<Integer>, DataType> threeDimensionalMap = Map.of(
    List.of(0,0,0), value000,
    List.of(0,0,1), value001,
    List.of(0,1,0), value010,
    List.of(0,1,1), value011,
    ...
)

This is not completely type-safe, since there's no check that all coordinates are of the same length, or that all coordinates are filled in, but it's a workable solution to some usecases.

Upvotes: 0

Related Questions