HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

A Java class that prints a matrix

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
classprintsjavathatmatrix

Problem

I am trying to learn some generic programming with Java:

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

/**
 * Created by PACKAGE_NAME on 15/11/14.
 */
public class PrintMatrix {
    public static  void printma(ArrayList> matrix) {
        ArrayList sizes = new ArrayList<>();
        for(ArrayList row : matrix) {
            sizes.add(row.size());
        }
        Set sizesSet = new HashSet<>(sizes);
        Integer[] sizesArray = sizesSet.toArray(new Integer[0]);
        Integer nCol = sizesArray[0];
        Integer nRow = matrix.size();

        if(sizesSet.size() > 1) {
            System.err.println("This is not a matrix.");
            return;
        }

        for(int i=0; i void printmb(ArrayList matrix) {
        ArrayList sizes = new ArrayList<>();
        for(T[] row : matrix) {
            sizes.add(row.length);
        }
        Set sizesSet = new HashSet<>(sizes);
        Integer[] sizesArray = sizesSet.toArray(new Integer[0]);
        Integer nCol = sizesArray[0];
        Integer nRow = matrix.size();

        if(sizesSet.size() > 1) {
            System.err.println("This is not a matrix.");
            return;
        }

        for(int i=0; i<nRow; i++) {
            for(int j=0; j<nCol; j++) {
                System.out.printf("%s\t", matrix.get(i)[j].toString());
            }
            System.out.println();
        }
    }
}

Solution

Your two print methods are odd in the sense that they are inconsistent with how you present them. A 'classic' matrix consists of primitive arrays (like int[][]), and not nested containers (like ArrayList>). I can understand why you have one and also the other, but the mix of them is bizarre, ArrayList. Remove the second print method.

Let's go through some other items first though. Let's narrow the ArrayList down to the interface level, just List. There is no reason to constrain the method to the concrete implementation because that severely restricts the applicability. I would actually go further and constrain it to Iterable. This produces the signature:

public static , M extends Iterable> void printMatrix(M matrix) {
    ....
}


What am I saying there? I am saying that the Matrix can consist of any combination of values that may have an Iterator. The mnemonics I use there are that:

  • T is the type of the cell data



  • R is the type of each row (which can be anything that is of type Iterable)



  • M is the combined Matrix, which can be any Iterable of ` (i.e. it's a collection of rows)



This is a generic method. You can throw pretty much anything at it from any collection structure.

An implementation of the method would look something like:

public static , M extends Iterable> void printMatrix(M matrix) {
    int size = -1;
    for (R row : matrix) {
        int s = 0;
        for (@SuppressWarnings("unused") T value : row) {
            s++;
        }
        if (size  0) {
            sb.setLength(sb.length()-1);
        }
        System.out.println(sb);
    }
}


and this could be used, for example, like:

public static void main(String[] args) {
    List> data = new ArrayList<>();
    data.add(System.getProperties().keySet());
    data.add(System.getProperties().values());
    printMatrix(data);
}


You should note a few things here:

  • The only reference to any concrete class here is the new ArrayList<>() in the main method. Everything else is treated at the lowest usable interface level (Collections, Lists, Iterables).



  • I use StringBuilder to build things 1 line at a time. This improves performance because each print is expensive, so you do fewer prints.



-
Java8 has a better way of counting the members, and also joining the Strings with the
\t character:

for (R row : matrix) {
    long s = StreamSupport.stream(row.spliterator(), false).count();
    if (size  sj.add(String.valueOf(v)));
    System.out.println(sj);
}


  • There is no need for the array-of-Integer to count the number of values in each line.



  • By putting the complexity of the generic types in the static method generics declaration area, the actual parameter has the simple type M`.

Code Snippets

public static <T, R extends Iterable<T>, M extends Iterable<R>> void printMatrix(M matrix) {
    ....
}
public static <T, R extends Iterable<T>, M extends Iterable<R>> void printMatrix(M matrix) {
    int size = -1;
    for (R row : matrix) {
        int s = 0;
        for (@SuppressWarnings("unused") T value : row) {
            s++;
        }
        if (size < 0) {
            size = s;
        } else if (size != s) {
            System.err.println("This is not a matrix.");
            return;
        }
    }

    StringBuilder sb = new StringBuilder();
    for (R row : matrix) {
        sb.setLength(0);
        for (T value : row) {
            sb.append(value).append('\t');
        }
        if (sb.length() > 0) {
            sb.setLength(sb.length()-1);
        }
        System.out.println(sb);
    }
}
public static void main(String[] args) {
    List<Collection<Object>> data = new ArrayList<>();
    data.add(System.getProperties().keySet());
    data.add(System.getProperties().values());
    printMatrix(data);
}
for (R row : matrix) {
    long s = StreamSupport.stream(row.spliterator(), false).count();
    if (size < 0) {
        size = s;
    } else if (size != s) {
        System.err.println("This is not a matrix.");
        return;
    }
}

for (R row : matrix) {
    StringJoiner sj = new StringJoiner("\t");
    row.forEach(v -> sj.add(String.valueOf(v)));
    System.out.println(sj);
}

Context

StackExchange Code Review Q#69958, answer score: 3

Revisions (0)

No revisions yet.