Referencing the Objects of 2D array into an ArrayList - java

I need to create an ArrayList from a 2D Array where the ArrayList works as a linear "view" of the array. The thing thats bothering me is that when I change the value of some element of the original Array, it doesnt change in the List. While debugging, I observed that the reference to the object in the array changes, but it stays the same in the list. This is how I initialize the List:
public class ColeccionArray2D<E> extends AbstractCollection<E> {
private ArrayList<E> data = new ArrayList<E>();
private int size = 0;
public ColeccionArray2D(E[][] contenido) {
data = twoDArrayToList(contenido);
this.size = data.size();
}
public ArrayList<E> twoDArrayToList(E[][] twoDArray) {
int index = 0;
ArrayList<E> list = new ArrayList<E>();
for (int i = 0; i < twoDArray.length; i++) {
for (int j = 0; j < twoDArray[i].length; j++) {
list.add(index, twoDArray[i][j]);
index++;
}
}
return list;
}
But if I change the original array:
arrayInteger[0][0] = -1;
The reference on the array changes, but it stays the same in the list, as in the Integer object doesn't change.
My best guess is that I need to "update" the view as operations happen, but it defeats the purpose of referencing the elements of the original array.
Is there a way to add the reference of the index (for example [0][0]) to the list? So when the object inside changes, it changes as well in the list?

I need to create an ArrayList from a 2D Array where the ArrayList works as a linear "view" of the array.
The code presented in the question indeed does not implement a view of the array. Instead, it just copies the contents of the array (shallowly) at one point in time, and is subsequently independent.
It is possible to create a custom List implementation that uses your 2D array as the backing element store. This could be implemented such that the List.set() method replaces the corresponding reference in the backing store with the one specified as an argument. This would be facilitated by extending AbstractList and overriding (only) get(), set(), and size().
But other than by doing similar with ArrayList as a base class, you cannot accomplish your aim with specifically an ArrayList. And using ArrayList as a base would be problematic, because some of the things one can do with an ArrayList, such as lengthening it with add() or shrinking it with remove(), do not make sense for a view of a fixed-size object such as an array.

Related

Why are ArrayList created with empty elements array but HashSet with null table?

Maybe a bit of a philosophical question.
Looking at java's ArrayList implementation I noticed that when creating a new instance, the internal "elementData" array (that holds the items) is created as new empty array:
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
However, a HashSet (that is based on a HashMap) is created with the table and entreySet are just left null;
transient Node<K,V>[] table;
transient Set<Map.Entry<K,V>> entrySet;
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
This got me thinking so I went and looked up C#'s List and HashSet:
https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,61f6a8d9f0c40f6e
https://referencesource.microsoft.com/#System.Core/System/Collections/Generic/HashSet.cs,2d265edc718b158b
List:
static readonly T[] _emptyArray = new T[0];
public List() {
_items = _emptyArray;
}
HashSet:
private int[] m_buckets;
public HashSet()
: this(EqualityComparer<T>.Default) { }
public HashSet(IEqualityComparer<T> comparer) {
if (comparer == null) {
comparer = EqualityComparer<T>.Default;
}
this.m_comparer = comparer;
m_lastIndex = 0;
m_count = 0;
m_freeList = -1;
m_version = 0;
}
So, is there a good reason why both languages picked empty for list and null for set/map?
They both used the "single instance" for the empty array trick, which is nice, but why not just have a null array?
Answering from a C# perspective.
For an empty ArrayList, you'll find that all the logic (get, add, grow, ...) works "as-is" if you have an empty array as backing store. No need for additional code to handle the uninitialized case, this makes the whole implementation neater. And since the empty array is cached, this does not result in an additional heap allocation, so you get the cleaner code at no extra cost.
For HashSet this is not possible, as accessing a bucket is done through the formula hashCode % m_buckets.Length. Trying to compute % 0 is considered as a division by 0, and therefore invalid. This means you need to handle specifically the "not initialized" case, so you gain nothing from pre-assigning the field with an empty array.
Initializing elementData to an empty array in ArrayList allows to avoid a null check in the grow(int minCapacity) method, which calls:
elementData = Arrays.copyOf(elementData, newCapacity);
to increase the capacity of the backing array. When that method is first called, that statement will "copy" the empty array to the start of the new array (actually it will copy nothing).
In HashMap a similar strategy wouldn't be useful, since when you re-size the array of buckets, you don't copy the original array to the start of the new array, you have to go over all the entries and find the new bucket of each entry. Therefore initialing the buckets array to an empty array instead of keeping it null will require you to check if the array's length == 0 instead of checking whether it's null. Replacing one condition with another wouldn't be useful.

ensureCapacity() for inner ArrayList

I have a 2-dimensional ArrayList Object
private ArrayList<ArrayList<Short>> VOL_2D = new ArrayList<ArrayList<Short>>();
Now I want to call .ensureCapacity() on both the outer list and all the inner lists (The number of inner lists is know, but they are not initialized yet). For the outer list it is easy, I just define how many inner lists I want to fit inside.
Is there a nice way of calling this method on the inner lists? Or do I have to call it every time I initialize a new inner list?
There's no thing like "2-dimensional ArrayList Object". You have an ArrayList which stores ArrayList objects inside it. All of objects stored in the outer list may have different sizes, some of them may be null or subclasses of ArrayList. So you have to explicitly add enough ArrayList objects into the outer array list:
int n = // size of the outer list
int m = // size of the inner lists
private ArrayList<ArrayList<Short>> VOL_2D = new ArrayList<ArrayList<Short>>(n);
for(int i=0; i<n; i++)
VOL_2D.add(new ArrayList<>(m));
Please note that ensureCapacity does not actually add any elements to the list. It just resizes the internal array to fit the specified number of elements, so subsequent resizes will not be necessary. Creating an empty ArrayList and calling ensureCapacity right after this is meaningless: better to use the ArrayList(minCapacity) constructor which will do the same in more effective way. Anyways ensureCapacity is useful just to improve the performance. If you actually want to have elements inside these lists, you may use:
for(int i=0; i<n; i++) {
ArrayList<Short> inner = new ArrayList<>(m);
for(int j=0; j<m; j++)
inner.add(null); // or some other initial value
VOL_2D.add(inner);
}
Finally if you want to have two-dimensional ArrayList of fixed size, why not just create array like this?
private short[][] VOL_2D = new short[n][m];
It would be much more performant.
It seems that you don't understand what this construct really means. You see, those "inner" lists have no idea that they might be collected in some outer list. So there is no way to (easily) achieve what you are looking for.
One possibility though: you could extend ArrayList; and in your own class, you can overwrite all methods that would "add" an ArrayList ... you can do whatever you want; for example set the desired capcity.
You don't need to call ensureCapacity
It's just a method used for optimisation to avoid unnecessary reallocation of the underlying array data structure.
From the docs
An application can increase the capacity of an ArrayList instance
before adding a large number of elements using the ensureCapacity
operation. This may reduce the amount of incremental reallocation.
If the outer ArrayList size is known, and fixed then I would recommend you to use array instead of ArrayList, like below.
int size = 10;
ArrayList<Short>[] VOL_2D = new ArrayList<Short>[size];
Why do you need to call ensureCapacity(int minCapacity)? Could you elaborate your usecase? Because when you create instance you can specify the size of ArrayList. like below
VOL_2D[0] = new ArrayList<Short>(30);
This will invoke below constructor, and create an array size of 30
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
To answer your question, there is no single in-built method which will iterate all elements in list and call ensureCapacity.
You need to write code for this, like below
for(ArrayList<Short> vol : VOL_2D){
vol.ensureCapacity(30);
}
Remember this, before call ensureCapacity method, you need to initialize your ArrayList object (in your case all inner ArrayList object), otherwise you will end up with NullPointerException.

Creating and filling an array in for each loop

//is there any way to do this
public Entry[] getArray(SimpleHashtable table) {
Entry[] data;
for (Entry k: table) {
//do something here
}
return data; //array that contains all elements stored in table
}
Is there a way to create and fill array with elements in for each loop?
Explained in short:
I have made class SimpleHashtable that stores objects, it implements Iterable.
Now I have to code method that returns an array of elements that are stored in that SimpleHashtable, and first idea that came to mind is to iterate over SimpleHashtable and fill array one element at the time, but I cant find any example of that.
If would like to avoid putting elements in a list in the meantime until I have iterated over SimpleHashtable (seems messy).
I know that arrays in Java aren't resizable, and that seems to make things difficult.
Assuming your class SimpleHashtable has a method size() to get the number of elements (which you need to size your array). You could then iterate with a for-each loop (as requested) with something like,
SimpleHashtable<Object> sh;
// ...
Object[] arr = new Object[sh.size()];
int pos = 0;
for (Object obj : sh) {
arr[pos++] = obj;
}

ArrayList Declaration - set unknown size

I am only in my 8th week of Java, so I am quite new.
I have a class that has an ArrayList object, list. I have another class called TransactionCalc. I would like for TransactionCalc to have its own ArrayList object, called arr3. I need to have be exactly as large as list. I know how to declare an ArrayList that is a size other than 10, but how do you do this if you do not yet know the exact size? Is it possible?
public class TransactionCalc extends CalculateAbstract{
private int count = 0;
private ArrayList <ItemAttribute> arr3 = new ArrayList <ItemAttribute> (1);
//the 1 needs to be list.size() ??
I am assuming that in the other class I will need to do public static final int = list.size(), but is it possible to get that constant over to the TransactionCalc class so that it can be in the declaration?
I forgot to add this... since the functionality of arrayList is not really needed, I could also do list.toArray(arr3) but that still wouldn't allow for it to be an object of the TransactionCalc class. Is it possible to do that? I'd like to avoid sending the same arr3 over and over again to multiple methods in the same class.
Also, how would I put this as a constructor?
EDIT with help from amaleemur____________
I have updated my code to have:
public class FindItemInfo implements InterfacePrint{
ArrayList <ItemAttribute> list = new ArrayList<ItemAttribute>();
//load arraylist and do something with it
//sort arraylist
public void printPriority(){
TransactionCalc finish = new TransactionCalc();
for (int i = 0; i < list.size(); i++){
for (int x = 0; x < list.size(); x++){
if(arr2.get(i) == list.get(x).getPriority()){
finish.cashOut(list.get(x), bankAccount, list.size());
} //send sorted arr2 to TransactionCalc class
}
}
public static int getListSize(){
return list.size();
}
}
public class TransactionCalc {//extends CalculateAbstract{
private int count = 0;
//private ArrayList <ItemAttribute> arr3 = new ArrayList <ItemAttribute> (FindItemInfo.getListSize());
private ItemAttribute[] arr3 = new ItemAttribute[FindItemInfo.getListSize()];
public void cashOut (ItemAttribute item, double bankAccount, int size) {
//ItemAttribute[] arr3 = new ItemAttribute[size];
double runningTotal = 0;
if((runningTotal + (item.getQuantity()*item.getPrice()))<= bankAccount){
runningTotal += item.getQuantity()*item.getPrice();
bankAccount -= runningTotal;
System.out.format("You will spend $%.2f on " + item.getQuantity() + " of "+ item.getDescription(), runningTotal);
System.out.format(" and have $%.2f left to spend\n", bankAccount);
}
else{
arr3[count] = item;
count++;
}
}
I am making arr3 an object of the TransactionCalc class because it is used for a few methods. The purpose of the array/arraylist is to collect the items that are not being printed. I can use either an array or an arraylist. I initially went with an array but then didn't know the size.
I am now getting static and non-static errors. When I go to try and fix this, it causes more problems.
The neat thing about using an ArrayList is that you don't have to declare a size.
so this is sufficient and you can add items to the array list.
private ArrayList <ItemAttribute> arr3 = new ArrayList <ItemAttribute>();
in order to get the size of list, I would suggest doing this:
In your class that contains the ArrayList list, create a method
public int getListSize(){
return list.size();
}
and now you can safely access the size of list. Does this help?
so now you'd do this:
private ArrayList <ItemAttribute> arr3 =
new ArrayList <ItemAttribute>(otherClass.getListSize());
where otherClass is a placeholder for the name of your other class with the ArrayList list.
ArrayList is a mutable collection type. This means (in this case) that instances of ArrayList may host arbitrary amounts of elements and in particular, the contained elements of a given instance of ArrayList may change at runtime. So you do not have to declare the amount of elements. In typical cases, you will most likely want to use the default c'tor (=not specify the initial amount of elements). Specifying the initial amount if elements may be a good idea (performance-wise), if you know that there will be a large number of objects inserted at run-time. In such cases, initialising an instance of ArrayList may safe some memory allocations an memcopy operations.

How can I make a resizable array in Java?

What is the best way to do a resizable array in Java? I tried using Vector, but that shifts all elements over by when when you do an insert, and I need an array that can grow but the elements stay in place. I'm sure there's a simple answer for this, but I still not quite sure.
As an alternative, you could use an ArrayList. It is a resizable-array implementation of the List interface.
Usage (using String):
List<String> myList = new ArrayList<String>();
myList.add("a");
myList.add("c");
myList.add("b");
The order will be just like you put them in: a, c, b.
You can also get an individual item like this:
String myString = myList.get(0);
Which will give you the 0th element: "a".
Like Sanjo pointed out: "An array is a static datastructure, so they can't grow". The list interface can by backed by an array(for example ArrayList like Kevin pointed out in his post). When the list structure is full and a new item has to be added to the list. Then the structure first creates a new array which can contain the old elements plus the new element which has to be added to the list.
The list interface has a different implementations which all have there pros/cons and you should pick the one best solving your problem-set. Below I will try to give a short summary when to use which implementation:
Not thread-safe implementations:
ArrayList: Resizable-array implementation of the List interface. You should use this implementation when you are doing a lot of size, isEmpty, get, set, iterator, and listIterator operations run in constant time. The add operation runs in amortized constant time, that is, adding n elements requires O(n) time. I think you should use this implementation when doing more lookups(get()) then adding items to list(add()).
LinkedList: This implementation is not backup by an array but "links" the nodes together. In my opinion you should use this implementation when you are doing more add() then get().
Thread-safe implementations:
Be aware that these list implementations aren't thread-safe which means it is possible to get race conditions when accesing them from multiple threads. If you want to use List implementations from multiple threads I would advise you to study the java.util.concurrent package and use implementation from that class.
You probably should use ArrayList instead of Vector for reasons explained in other answers.
However ...
I tried using Vector, but that shifts all elements over by when when you do an insert, and I need an array that can grow but the elements stay in place.
When you do an insertElementAt(pos, elem), you have specifically asked for the element shifting. If you don't want the elements to be shifted, you should use set(pos, elem) instead. Or if you want to add the element at the end of the vector, you can also use add(elem).
Incidentally, the previous paragraph applies to all implementations of List, not just Vector, though the implementation details and performance vary across the different kinds of List.
I tried using Vector, but that shifts all elements over by when when you do an insert, and I need an array that can grow but the elements stay in place.
You probably want to use ArrayList instead of Vector.
They both provide about the same interface, and you can replace elements with both of them by calling set(idx, element). That does not do any shifting around. It also does not allow you to grow the array, though: You can only insert at already occupied positions (not beyond the current size of the array), to add new elements at the end you have to use add(element).
The difference between ArrayList and Vector is that Vector has synchronization code which you most likely do not need, which makes ArrayList a little faster.
If you want to operate array data after all element had already inserted or deleted, there is a way that try to create a LinkedList or ArrayList, its simply resize, after the data input is finished, you can transfer the ArrayList to an Array, then do all the things you normally to Array.
ArrayList and LinkedList
Space Complexity:
a) ArrayList:
Allocates a chunk of memory when you initialize and doubles everytime it reaches it max size whenever you add an element dynamically.
b) LinkedList:
It allocates memory only everytime you add an item to the list.
Runtime Complexity:
a) ArrayList:
Search is faster, insertion and deletion is slower compared to linked list
b) LinkedList:
Insertion and deletion is faster, search is slower compared to array list
An array cannot be resized dynamically in Java. The solution to this is using ArrayList or creating another temporary array and then assign it.
You can find tutorials about ArrayList, but if you just want custom ResizableArray in Java. Here's it is. But it's NOT recommend to use! It's just a FAKE resizable array and heap memory will be increased when you create too many objects. This is just to show you the idea.
The Interface
public interface Resizable<T> {
void add(T data);
int delete(int index);
int size();
void print();
}
Implementation Class
public class ResizeableImpl<T> implements Resizable<T> {
private Object[] temp = null;
private Object[] originals = new Object[0];
#Override
public void add(T data) {
Object[] temp = new Object[originals.length+1];
for (int i=0; i<originals.length; i++) {
temp[i]=originals[i];
}
temp[originals.length]=data;
originals=temp;
}
#Override
public int delete(int index) {
int success=0;
switch (originals.length) {
case 0: //No Data to delete
success=0;
break;
case 1: //One Data is delete and so no data, too!
originals = new Object[0];
success = 1;
break;
default: //>=2
int count=0;
originals[index]=null;
temp = new Object[originals.length-1];
for (int i=0; i<originals.length; i++) {
if (originals[i]!=null)
temp[count++]=originals[i];
}
originals = temp;
success = 1;
}
return success;
}
#Override
public int size() {
return originals.length;
}
#Override
public void print() {
StringBuilder sb = null;
if (originals.length==0) {
System.out.println("No data available!");
return;
}
for (int i=0; i<originals.length; i++) {
if (sb==null) {
sb = new StringBuilder();
sb.append(originals[i]);
}
else {
sb.append(", "+originals[i]);
}
}
sb.append(".");
System.out.println(sb.toString());
}
}
Main method
public class App {
public static void main(String[] args) {
//Program to interfaces, not implementations
Resizable<Integer> obj = new ResizeableImpl<>();
obj.add(13);
obj.add(20);
obj.add(17);
obj.add(25);
obj.add(100);
obj.add(12);
obj.print();
int result = obj.delete(2); //This will delete 17.
if (result==1) {
System.out.println("Deletion is successful!");
}
obj.print();
obj.delete(3); //This will delete 100.
obj.print();
}
}
Output
13, 20, 17, 25, 100, 12.
Deletion is successful!
13, 20, 25, 100, 12.
13, 20, 25, 12.
Use either ArrayList or LinkedList.
Using wonderful classes in Collections framework is the better than using arrays.
But in case your question is from a "quizzing" perspective, here is what you should do.
Create your own resize method such as:
int[] oldArray = {1,2,3};
int oldSize = java.lang.reflect.Array.getLength(oldArray);
Class elementType = oldArray.getClass().getComponentType();
Object newArray = java.lang.reflect.Array.newInstance(
elementType,newSize);
int preserveLength = Math.min(oldSize,newSize);
if (preserveLength > 0)
System.arraycopy (oldArray,0,newArray,0,preserveLength);
oldArray = newArray;

Categories

Resources