How does one access an ArrayList of ArrayLists? (Generics?) - java

I'm trying to create a table class, who's rows and columns may expand or shrink, to store ints and strings as a first Java project. The data structure I'm trying to use to represent the table is an ArrayList of ArrayLists, where the initial array's elements all point to a new array list - so the initial array kind of serves as an entrance into rows. This would be a picture of how I have it in my mind, for reference:
The problem I'm having is accessing the inner ArrayLists. I've been reading a bit of documentation, and I can't seem to understand the big issue with why I'm not able to access the inner lists. Some code here:
import java.util.ArrayList;
public class Table {
private int length, width;
private ArrayList newTable;
public Table() {
this.length = this.width = 0;
}
/**
* Testing a few functions
*/
public static void main(String[] args) {
// Just testing a few functions.
Table list1 = new Table();
list1.createTable(4, 4);
list1.displayRow(1);
list1.displayColumn(1);
System.out.println("displayColumn done!");
list1.displayEntireTable();
}
public void createTable(int tableLength, int tableWidth) {
length = tableLength;
width = tableWidth;
this.newTable = new ArrayList();
for (int i = 0; i < tableWidth; i++) {
this.newTable.add(new ArrayList(tableLength));
}
}
public void displayRow(int row) {
System.out.println(this.newTable.get(row));
}
/**
* This function displays the column of the table. Still work which
* needs to be done here.
* #param column
*/
public void displayColumn(int column) {
if (this.newTable.size() >= column) {
for (int i = 0; i < this.newTable.size(); i++) {
// This doesn't work.
System.out.println(this.newTable.get(i).get(column));
}
}
}
public void displayEntireTable() {
for (int i = 0; i < this.newTable.size(); i++) {
System.out.println(this.newTable.get(i));
}
}
}
I'm suspicious that the problem may rely the lack of use in generics, which I'm not quite as familiar with yet as I would like to be. So my question to you, stackoverflow, is whether this data structure - an ArrayList of ArrayLists - is even possible, and if so, where lays my problem?

I think the problem is that you misunderstood the semantics of the new ArrayList(tableLength) call: it does not create an array list of tableLength elements; rather, it creates an ArrayList with the initial capacity enough to hold at least tableLength elements.
I am not sure what kind of elements you are planning to add to your ArrayList of ArrayLists, but here is one way to test your code that creates a two-dimensional ArrayList:
for (int i = 0; i < tableWidth; i++) {
ArrayList toAdd = new ArrayList(tableLength);
for (int j = 0; j != tableLength ; j++) {
toAdd.add(new Integer(i*tableLength +j));
}
this.newTable.add(toAdd);
}

Using Java 1.7 generics improvements:
import java.util.ArrayList;
import java.util.List;
public class Table {
private int length, width;
private List<List<String>> newTable;
public Table() {
this.length = this.width = 0;
}
/**
* Testing a few functions
*/
public static void main(String[] args) {
// Just testing a few functions.
Table list1 = new Table();
list1.createTable(4, 4);
list1.displayRow(1);
System.out.println("displayRow done!");
list1.displayColumn(1);
System.out.println("displayColumn done!");
list1.displayEntireTable();
System.out.println("displayEntireTable done!");
}
public void createTable(int tableLength, int tableWidth) {
length = tableLength;
width = tableWidth;
//by java 1.7 diamond feature, some generics can be hidden
this.newTable = new ArrayList<>();
for (int i = 0; i < tableWidth; i++) {
List<String> columns = new ArrayList<>();
for (int j = 0; j < tableLength; j++) {
columns.add(new String("test"));
} //added here
this.newTable.add(columns);
}
}
public void displayRow(int row) {
System.out.println(this.newTable.get(row));
}
/**
* This function displays the column of the table. Still work which
* needs to be done here.
* #param column
*/
public void displayColumn(int column) {
for (int i = 0; i < this.newTable.size(); i++) {
System.out.println("[" + this.newTable.get(i).get(column) + "]");
}
}
public void displayEntireTable() {
for (int i = 0; i < this.newTable.size(); i++) {
System.out.println(this.newTable.get(i));
}
}
}

Sure it's possible, and I suspect your issues are related to generics, actually -- if you don't use generics, you'll have to do a bunch of casts, which may appear to you as if it just doesn't work.
I'd write this as something like
List<List<Object>> table;
and then I'd add rows by doing table.add(new ArrayList<Object>()), and access elements with table.get(i).get(j).

First of all, what is your real problem? You don't add any data into the inner ArrayLists, so they are empty.
On the other hand, it is better if you create an object for a row, and store these objects in an arraylist.

Change your code that doesn't work to:
System.out.println(((ArrayList) this.newTable.get(i)).get(column));
ArrayList in ArrayList is certainly possibly.
And it is certainly not generics that prohibits you.
Generics is only a compile time check for mistakes and has nothing to do with it. You can complete leave it out, not advised as the probability for class cast exceptions due too mistakes is far larger.
Explanation. The compiler don't knows your ArrayList contains an ArrayList so it doesn't recognize the get method as it trys to invoke it on Object and not ArrayList. So the solution is to cast it if you wan't to use it without generics. However I would recomend to use generics and define your List like this.
private List<List<String> newTable;
Notice how I used List and not ArrayList. Typically your left hand assignment contains an Interface and the right hand an concrete class like ArrayList.

Related

how can i make get the original layout of the arraylist?

so i've created this function as a game :
public static ArrayList<Character> spreadCardsOnTable(char[] cards) {
ArrayList<Character> newCards = new ArrayList<Character>();
Queue<Character> q = new LinkedList<>();
while (cards.length != 0) {
int k = 0;
for (int i = 0; i <= cards.length - 1; i++) {
if (i % 2 == 0) {
newCards.add(cards[i]);
} else {
q.add(cards[i]);
k++;
}
}
cards = new char[k];
for (int j = 0; j <= k - 1; j++) {
cards[j] = q.poll();
}
}
return newCards;
}
the game goes as for example if we have an array made of ['W','B','B','B','W','W']
after i run the function i made i get an output of ['W','B','W','B','W','B'] as it is now organized
now on the second function i need to do is: given an int "n" i should find the original array ['W','B','B','B','W','W'] before sending it to the first function and organizing it as the example goes ['W','B','W','B','W','B'] like reversing it, i've tried several ways but all of them failed
the title of the function is :
public static ArrayList createOriginalLayout(int n)
No. Once you've dereferenced the original list then it's original indexing is gone unless you preserve the original sorting order within the items in the list itself, but that would be very strange.
What I'd do is create a class to hold the original data and offer up a presentation function for the sorted data. Something like:
public class CardLayout {
private List<Character> originalList;
public CardLayout(List<Character> list) {
originalList = list;
}
public List<Character> getOriginalList() {
return originalList;
}
public List<Character> getSortedList() {
//edit: Note that your original method is destructive to
//the original data, so you would need to copy the data
//into another structure before proceeding.
//either do your spreadCardsOnTable() method here or
//precalculate it, store it, and return it here.
}
}

Collections is private

I keep getting a "collections is private" error. I wanted to create an ArrayList. How do you properly extend the Collections class?
import java.util.Collections;
public class lists extends Collections {
public static void main(String[] args) {
Arraylist <Integer> x = new Arraylist<>();
int[] y = new int[100];
for(int i = 0; i<100-1; i++) {
y[i] = i;
}
for(int j = 0; j<100-1; j++) {
Integer z = new Integer(y[j]);
x.set( j , z );
System.out.println(x.get(j));
}
}
}
Perhaps if you are only trying to use ArrayList then you don't need to extend that.
It's ArrayList (not Arraylist)
Use y.length on your first loop rather than 100-1.
You can just use x.add() to add your integer value in without setting index it should be added into since there you are strictly specifying a pattern.
Try this solution:
import java.util.ArrayList;
public static void main (String[] args) throws java.lang.Exception
{
ArrayList <Integer> x = new ArrayList<Integer>();
int[] y = new int[100];
for(int i = 0; i<y.length; i++){
y[i] = i;
}
for(int j = 0; j<100-1; j++){
x.add(new Integer(y[j]));
System.out.println(x.get(j));
}
}
But, here is better solution, same achievement with one loop:
public static void main (String[] args) throws java.lang.Exception
{
ArrayList <Integer> x = new ArrayList<>();
for(int j = 0; j<100-1; j++){
x.add(new Integer(j));
System.out.println(x.get(j));
}
}
First off, if all you want to do is create an instance of ArrayList, there's no reason to extend anything. In your example code there's no need for it.
If you really do want your own collection class, then Collections is the wrong class. You need to implement Collection<E>, singular, or List<E>.
Implementing those interfaces is a lot of work. You can save a lot of time by sub-classing AbstractList<E>. When you do that you only have to implement get(int) and size(); the rest is done for you. If the list is modifiable then you'll also want to override set(int, E), add(int, E), and remove(int).
From the source of Collections class. Collections class is non-instantiable since it has a private constructor. If you have a Subclass which calls the Collections class, the subclass will invoke the super class constructor since the super class does not define any other constructor to invoke. You cannot instantiate the Collections super class and its sub-classes.
// Suppresses default constructor, ensuring non-instantiability.
private Collections() {
}
From your question, if you want to just instantiate an ArrayList class. The line ArrayList <Integer> x = new ArrayList<>(); will suffice with an import of java.util.ArrayList.
Check your code and add variables where needed and you can improve further on the logic.
final int RANGEVAL = 100;
for(int i = 0; i < RANGEVAL -1 ; i++) {
x.set( i , i ); //You can also use x.add(i);
System.out.println(x.get(i));
}

creating java generic data structure

I am building a data structure to learn more about java. I understand this program might be useless.
Here's what I want. I want to create a data structure that store smallest 3 values. if value is high, then ignore it. When storing values than I also want to put them in correct place so I don't have to sort them later. I can enter values by calling the add method.
so let's say I want to add 20, 10, 40, 30 than the result will be [10,20,30]. note I can only hold 3 smallest values and it store them as I place them.
I also understand that there are a lot of better ways for doing this but again this is just for learning purposes.
Question: I need help creating add method. I wrote some code but I am getting stuck with add method. Please help.
My Thinking: we might have to use a Iterator in add method?
public class MyJavaApp {
public static void main(String[] args){
MyClass<Integer> m = new MyClass<Integer>(3);
m.add(10);
m.add(20);
m.add(30);
m.add(40);
}
}
public class MyClass<V extends Comparable<V>> {
private V v[];
public MyClass(int s){
this.v = (V[])new Object[s];
}
public void add(V a){
}
}
Here is a rough sketch of the add method you have to implement.
You have to use the appropriate implementation of the compareTo method when comparing elements.
public void add(V a){
V temp = null;
if(a.compareTo( v[0]) == -1 ){
/*
keeping the v[0] in a temp variable since, v[0] could be the second
smallest value or the third smallest value.
Therefore call add method again to assign it to the correct
position.
*/
temp = v[0];
v[0] = a;
add(temp);
}else if(a.compareTo(v[0]) == 1 && a.compareTo(v[1]) == -1){
temp = v[1];
v[1] = a;
add(temp);
}else if(a.compareTo(v[1]) == 1 && a.compareTo(v[2]) == -1){
temp = v[2];
v[2] = a;
add(temp);
}
}
Therefore the v array will contain the lowerest elements.
Hope this helps.
A naive, inefficient approach would be (as you suggest) to iterate through the values and add / remove based on what you find:
public void add(Integer a)
{
// If fewer than 3 elements in the list, add and we're done.
if (m.size() < 3)
{
m.add(a);
return;
}
// If there's 3 elements, find the maximum.
int max = Integer.MIN_VALUE;
int index = -1;
for (int i=0; i<3; i++) {
int v = m.get(i);
if (v > max) {
max = v;
index = i;
}
}
// If a is less than the max, we need to add it and remove the existing max.
if (a < max) {
m.remove(index);
m.add(a);
}
}
Note: this has been written for Integer, not a generic type V. You'll need to generalise. It also doesn't keep the list sorted - another of your requirements.
Here's an implementation of that algorithm. It consists of looking for the right place to insert. Then it can be optimized for your requirements:
Don't bother looking past the size you want
Don't add more items than necessary
Here's the code. I added the toString() method for convenience. Only the add() method is interesting. Also this implementation is a bit more flexible as it respects the size you give to the constructor and doesn't assume 3.
I used a List rather than an array because it makes dealing with generics a lot easier. You'll find that using an array of generics makes using your class a bit more ugly (i.e. you have to deal with type erasure by providing a Class<V>).
import java.util.*;
public class MyClass<V extends Comparable<V>> {
private int s;
private List<V> v;
public MyClass(int s) {
this.s = s;
this.v = new ArrayList<V>(s);
}
public void add(V a) {
int i=0;
int l = v.size();
// Find the right index
while(i<l && v.get(i).compareTo(a) < 0) i++;
if(i<s) {
v.add(i, a);
// Truncate the list to make sure we don't store more values than needed
if(v.size() > s) v.remove(v.size()-1);
}
}
public String toString() {
StringBuilder result = new StringBuilder();
for(V item : v) {
result.append(item).append(',');
}
return result.toString();
}
}

Java: How to use functions of a class which has been instantiated by ArrayList

Here is just a simple example. Obviously there are simpler ways to set everything up within the constructor, but the arrayList I'm actually working with has already been set up, I just need to change individual sections of it. There HAS to be a way to call a class's functions in ArrayList, but for the life of me I can't figure out how.
import java.util.ArrayList;
public class ArrayTest{
public static void main(String[] args){
//Here's an example of a regular array:
Length[] lArray = new Length[3];
for (int i = 0; i < 3; i++){
lArray[i].setLength(i + 1);
}
//Here's how I was hoping ArrayList would function:
ArrayList<Length> lList = new ArrayList<Length>(3);
for (int i = 0; i < 3; i++){
lList[i].setLength(i + 1);
// --OR--
lList.setLength(i, i + 1);
}
}
}
Here's the length class:
public class Length{
private int length;
Length(){
length = 0;
}
Length(int s){
length = s;
}
public void setLength(int s){
length = s;
}
}
Thanks!
You add elements to the ArrayList with add.
Since it's an ArrayList<Length>, you add Length objects:
lList.add(new Length());
And in your specific loop :
ArrayList<Length> lList = new ArrayList<Length>(3);
for (int i = 0; i < 3; i++){
Length l = new Length();
l.setLength(i+1);
lList.add(l);
}
BTW, the array initialization is also missing an important initialization :
for (int i = 0; i < 3; i++){
lArray[i] = new Length(); // added
lArray[i].setLength(i + 1);
}
If the ArrayList already contains the elements, and you just want to modify them, you can write something like this:
lList.get(i).setLength(i + 1);
assuming that the ArrayList contains the ith element.
You could create a method with your operation/algorithm like
public void foo(){
System.out.println("some algorithm!");
}
inside Length class. This will operate on each instance of Length class.
And for iterating, you can use
ArrayList<Length> lList = new ArrayList<Length>(3);
for (Length l : lList){
l.foo();
}
This will call everything you code inside foo.

How to display object as a String properly

Im working on this code and expecting a matrix to be printed but thats what came up
Matrix#2c78bc3b Matrix#2a8ddc4c
This is a code example:
public class Matrix
{
public static int rows;
public static int colms;//columns
public static int[][] numbers;
public Matrix(int[][] numbers)
{
numbers = new int[rows][colms];
}
public static boolean isSquareMatrix(Matrix m)
{
//rows = numbers.length;
//colms = numbers[0].length;
if(rows == colms)
return true;
else
return false;
}
public static Matrix getTranspose(Matrix trans)
{
trans = new Matrix(numbers);
for(int i =0; i < rows; i++)
{
for(int j = 0; j < colms; j++)
{
trans.numbers[i][j] = numbers[j][i];
}
}
return trans;
}
public static void main(String[] args)
{
int[][] m1 = new int[][]{{1,4}, {5,3}};
Matrix Mat = new Matrix(m1);
System.out.print(Mat);
System.out.print(getTranspose(Mat));
}
}
You need to implement toString() in a meaningful way.
This toString() (below) is perhaps suitable for debugging, but will be ugly and confusing if you use it for real user output. An actual solution would probably use a Formatter in some complicated way to produce neatly tabular rows and columns.
Some additional recommendations based on your code:
Suggest not storing the rows/columns sizes separately. SSOT / Single Source of Truth or DRY, Java+DRY. Just use the .length, and provide accessor methods if need be.
Use final in method args, it will eliminate bugs like you have above, aliasing numbers incorrectly int the constructor
Use an instance, not static
Paranoia is the programmer's lifestyle: I also modified my code to do a deepCopy of the provided int[][] array, otherwise there is reference leakage, and the Matrix class would be unable to enforce its own invariants if caller code later modified the int[][] they passed in.
I made my Matrix immutable (see final private numbers[][]) out of habit. This is a good practice, unless you come up with a good reason for a mutable implementation (wouldn't be surprising for performance reasons in matrices).
Here's some improved code:
public final class Matrix
{
final private int[][] numbers;
// note the final, which would find a bug in your cited code above...
public Matrix(final int[][] numbers)
{
// by enforcing these assumptions / invariants here, you don't need to deal
// with checking them in other parts of the code. This is long enough that you might
// factor it out into a private void sanityCheck() method, which could be
// applied elsewhere when there are non-trivial mutations of the internal state
if (numbers == null || numbers.length == 0)
throw new NullPointerException("Matrix can't have null contents or zero rows");
final int columns = numbers[0].length;
if (columns == 0)
throw new IllegalArgumentException("Matrix can't have zero columns");
for (int i =1; i < numbers.length; i++) {
if (numbers[i] == null)
throw new NullPointerException("Matrix can't have null row "+i);
if (numbers[i].length != columns)
throw new IllegalArgumentException("Matrix can't have differing row lengths!");
}
this.numbers = deepCopy(numbers);
}
public boolean isSquareMatrix() { return rowCount() == columnCount(); }
public int rowCount() { return numbers.length; }
public int columnCount() {return numbers[0].length; }
private static int[][] deepCopy(final int[][] source)
{
// note we ignore error cases that don't apply because of
// invariants in the constructor:
assert(source != null); assert(source.length != 0);
assert(source[0] != null); assert(source[0].length != 0);
int[][] target = new int[source.length][source[0].length];
for (int i = 0; i < source.length; i++)
target[i] = Arrays.copyOf(source[i],source[i].length);
return target;
}
public Matrix getTranspose()
{
int[][] trans = new int[columnCount()][rowCount()];
for (int i = 0; i < rowCount(); i++)
for (int j = 0; j < columnCount(); j++)
trans[i][j] = getValue(j, i);
return new Matrix(trans);
}
#Override
public String toString()
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < numbers.length; i++)
{
for (int j = 0; j < numbers[i].length; j++)
sb.append(' ').append(numbers[i][j]);
sb.append('\n');
}
return sb.toString();
}
public static void main(String[] args)
{
final int[][] m1 = new int[][] { { 1, 4 }, { 5, 3 } };
Matrix mat = new Matrix(m1);
System.out.print(mat);
System.out.print(mat.getTranspose());
}
}
for a quick and dirty method:
public String toString() {
return Arrays.deepToString(numbers);
}
On an unrelated note, the variables rows, colms, numbers and the methods isSquareMatrix should not be declared as static. Otherwise, when you get a transpose, you're going to end up with two matrix objects writing to the same class variables.
You didn't define a toString method for your Matrix class, so when you try to print a Matrix you see the result of the default toString method which prints the object's class and unique id.
System.out.print(Mat);
it will call the toString method of the Matrix class.
So, if you want to print your Matrix, you will have to override toString method
#Override
public String toString() {
// create here a String representation of your matrix
// ie: String myString = "1 0 0 1\n0 1 1 1\n...";
return "String representation of my matrix";
}
To display the Matrix class object when you can print on it you'll have to define the toString method in your class.
Another bug in the code it you are not setting the value of rows and colms. So when you do
numbers = new int[rows][colms];
in your constructor, rows and colms will always have their default value of 0. You need to fix that. And then you'll have to copy the matrix elements from the parameter array to numbers.

Categories