Reputation: 553
I have a method that will need to return a set of data, and the current plan is to use an ArrayList of ArrayList, however I am unsure if there is a collection that is more suitable.
This abstract nature lead me to believe that each row would be best represented by an ArrayList, as this could has entries added to it before finally adding that ArrayList to the main ArrayList.
Is there a better way to do this, particularly with regards to performance?
Upvotes: 1
Views: 64
Reputation: 3166
In Java, there is the concept of Jagged Arrays. It's essentially that same as you describe. You can either implement it in one of two ways.
2-D Array Approach
// Initialize the rows only for now
String[][] arr = new String[3][];
// Process some data to know the column sizes of each
// ...
arr[0] = new String[] {"Foo", "Bar", "FooBar"};
arr[1] = new String[] {"Jane", "Doe"};
arr[2] = new String[] {"Peter", "Parker", "Tony", "Stark"};
// ...
// Printing
for(String[] row : arr) {
System.out.println(Arrays.ToString(row));
}
Array of Lists Approach
// Initialize the rows only for now
List<String> [] arr = new List[3];
// Process some data
// ...
List<String> list1 = new ArrayList<>();
list1.add("Foo");
list1.add("Bar");
list1.add("FooBar");
List<String> list2 = new ArrayList<>();
list2.add("Jane");
list2.add("Doe");
List<String> list3 = new ArrayList<>();
list3.add("Peter");
list3.add("Parker");
list3.add("Tony");
list3.add("Stark");
// ...
// Printing
for(int i = 0 ; i < arr.length; i++) {
List<String> temp = arr[i];
System.out.println(temp);
}
Based on your needs, since you know that your data set will always remain fixed. You just don't know the length of each row in the Jagged Array. Based on this, Go with the plain 2-D approach.
Now, If you think the requirements are going to change later down the road, or you like the useful methods that ArrayLists
have (contains
etc.) then I would go with an Array
of ArrayLists
.
You will not notice a significant performance difference between the two implementations unless the data set is huge. If you are experiencing performance issues then go with the 2-D array approach.
If it was up to me, I would go with the Array
of ArrayLists
approach. I would go with this because:
ArrayLists
can be expanded easily if your data set would ever happen to change.ArrayLists
also offer plenty useful methods that are easier to just call then have to implement yourself.ArrayLists
also they implement Iterable
, Collection
, and List
, and can therefore be used in a lot of API calls that are interface-based.Some methods that ArrayLists
can do are here.
More about Jagged arrays can be found here.
Upvotes: 1
Reputation: 778
There is little complicated way (But performance is good because of direct access to data) how the have the collection which has the row represented by groupKey (rowKey) and colums represented by comlunKey. Here you can add optional object. In simple way it is map of maps.
/**
* representation of bi dimensional array with dynamical size
*
* @param <K> - type of row key
* @param <L> - type of columne key
* @param <V> - type of value
*/
public class CustomCollection<K, L, V> extends HashMap<K, Map<L, V>> {
public CustomCollection() {
}
/**
* add new entry on particular row and column
*
* @param rowKey - key of row
* @param columnKey - key of column
* @param value - value to add
*/
public void addNewEntry(K rowKey, L columnKey, V value) {
Map<L, V> columns = get(rowKey);
if (columns == null) {
columns = new HashMap<>();
put(rowKey, columns);
}
columns.put(columnKey, value);
}
/**
* get exact value on current row represented by {@code rowKey} and column represented by {@code columnKey}
*
* @param rowKey - key of row
* @param columnKey - key of column
* @return
*/
public V getExactValue(K rowKey, V columnKey) {
Map<L, V> columns = get(rowKey);
if (columns == null) {
return null;
}
return columns.get(columnKey);
}
/**
* get colums values as map
*
* @param rowKey - key of row
* @return
*/
public Map<L, V> getColumsAsMap(K rowKey) {
return get(rowKey);
}
/**
* get colums values as map
*
* @param rowKey - key of row
* @return
*/
public Collection<V> getColumsAsCollection(K rowKey) {
Map<L, V> columns = get(rowKey);
if (columns == null) {
return null;
}
return columns.values();
}
/**
* remove value on particular index
*
* @param rowKey
* @param columnKey
*
* @return - removed item
*/
public V removeExactValue(K rowKey, L columnKey){
Map<L, V> columns = get(rowKey);
if (columns == null) {
return null;
}
return columns.remove(columnKey);
}
@Override
public String toString(){
final StringBuffer stringBuffer = new StringBuffer();
keySet().forEach(rowKey -> {
stringBuffer.append(rowKey + " = {");
Map<L, V> columns = get(rowKey);
if (columns != null) {
columns.entrySet().forEach(entry -> {
stringBuffer.append("["+entry.getKey()+"="+entry.getValue()+"]");
});
}
stringBuffer.append("}\n");
});
return stringBuffer.toString();
}
}
// Sample how to use it
public static void main(String [] args){
CustomCollection<Integer,Integer,String> customCollection = new CustomCollection<>();
customCollection.addNewEntry(1,1, "v_1_1");
customCollection.addNewEntry(1,2,"v_1_2");
customCollection.addNewEntry(2,1,"v_2_1");
customCollection.addNewEntry(2,2,"v_2_2");
customCollection.addNewEntry(2,3,"v_2_3");
System.out.println(customCollection.toString());
System.out.println("After remove:");
customCollection.removeExactValue(2,2);
customCollection.removeExactValue(2,3);
System.out.println(customCollection.toString());
}
Upvotes: 1
Reputation: 14611
IF the number of rows is fixed (let us say 10) and the number off columns not, then you can use an array of lists like e.g:
// Use whatever type you need instead of Integer.
@SuppressWarnings("unchecked")
List<Integer>[] arrayOfLists = new ArrayList[10];
This code issues a warning "generic array creation". For this reason I have added @SuppressWarnings("unchecked")
.
Upvotes: 1