3030
3131package org .scijava .table ;
3232
33+ import java .util .Collection ;
34+ import java .util .List ;
35+ import java .util .Map ;
36+ import java .util .Objects ;
37+
3338/**
3439 * Utility methods for constructing tables.
3540 *
@@ -41,6 +46,99 @@ private Tables() {
4146 // NB: Prevent instantiation of utility class.
4247 }
4348
49+ /**
50+ * Creates a table wrapping a list of maps. Each map is one row of the table.
51+ * Map keys are column names; map values are cell data.
52+ * <p>
53+ * Note that columns are inferred from the first map/row of the table, not
54+ * unioned across all rows.
55+ * </p>
56+ *
57+ * @param data The data to wrap. Each list element is a row; maps go from
58+ * column name to data.
59+ * @param rowHeaders List of row header labels. Pass null for no row headers.
60+ * @return A {@link Table} object wrapping the data structure.
61+ */
62+ public static <T > Table <Column <T >, T > wrap (
63+ final List <? extends Map <?, ? extends T >> data , final List <String > rowHeaders )
64+ {
65+ if (data .isEmpty ()) throw new IllegalArgumentException ("Cannot wrap an empty list" );
66+
67+ return new ReadOnlyTable <T >() {
68+
69+ @ Override
70+ public int getRowCount () {
71+ return data .size ();
72+ }
73+
74+ @ Override
75+ public String getRowHeader (final int row ) {
76+ if (rowHeaders == null || rowHeaders .size () < row ) return null ;
77+ return rowHeaders .get (row );
78+ }
79+
80+ @ Override
81+ public int size () {
82+ return data .get (0 ).size ();
83+ }
84+
85+ @ Override
86+ public Column <T > get (final int col ) {
87+ class ColumnAccessor implements ReadOnlyColumn <T > {
88+
89+ private final Object tableData = data ;
90+ private boolean initialized ;
91+ private String colHeader ;
92+
93+ @ Override
94+ public String getHeader () {
95+ if (!initialized ) {
96+ int c = 0 ;
97+ for (final Object key : data .get (0 ).keySet ()) {
98+ if (col == c ++) {
99+ colHeader = key == null ? "<null>" : key .toString ();
100+ break ;
101+ }
102+ }
103+ initialized = true ;
104+ }
105+ return colHeader ;
106+ }
107+
108+ @ Override
109+ public int size () {
110+ return data .size ();
111+ }
112+
113+ @ Override
114+ public Class <T > getType () {
115+ // TODO: Consider whether this is terrible.
116+ throw new UnsupportedOperationException ();
117+ }
118+
119+ @ Override
120+ public T get (final int index ) {
121+ return data .get (index ).get (getHeader ());
122+ }
123+
124+ @ Override
125+ public int hashCode () {
126+ return getHeader ().hashCode ();
127+ }
128+
129+ @ Override
130+ public boolean equals (final Object obj ) {
131+ if (!(obj instanceof ColumnAccessor )) return false ;
132+ final ColumnAccessor other = ((ColumnAccessor ) obj );
133+ if (data != other .tableData ) return false ;
134+ return Objects .equals (getHeader (), other .getHeader ());
135+ }
136+ }
137+ return new ColumnAccessor ();
138+ }
139+ };
140+ }
141+
44142 // -- Internal methods --
45143
46144 /**
@@ -98,4 +196,158 @@ private static void check(final String name, final int index, final int count,
98196 throw new IndexOutOfBoundsException ("Invalid " + name + "s: " + index +
99197 " - " + last );
100198 }
199+
200+ private static UnsupportedOperationException readOnlyException () {
201+ return new UnsupportedOperationException ("Wrapped table is read-only" );
202+ }
203+
204+ // -- Helper classes --
205+
206+ /** Read-only version of a {@link Table}. */
207+ private static interface ReadOnlyTable <T > extends Table <Column <T >, T > {
208+
209+ @ Override
210+ default void setColumnCount (final int colCount ) {
211+ throw readOnlyException ();
212+ }
213+
214+ @ Override
215+ default List <Column <T >> insertColumns (final int col , final int count ) {
216+ throw readOnlyException ();
217+ }
218+
219+ @ Override
220+ default void setRowCount (final int rowCount ) {
221+ throw readOnlyException ();
222+ }
223+
224+ @ Override
225+ default void removeRows (int row , int count ) {
226+ throw readOnlyException ();
227+ }
228+
229+ @ Override
230+ default void setRowHeader (int row , String header ) {
231+ throw readOnlyException ();
232+ }
233+
234+ @ Override
235+ default void set (String colHeader , int row , T value ) {
236+ throw readOnlyException ();
237+ }
238+
239+ @ Override
240+ default boolean add (final Column <T > column ) {
241+ throw readOnlyException ();
242+ }
243+
244+ @ Override
245+ default boolean remove (final Object column ) {
246+ throw readOnlyException ();
247+ }
248+
249+ @ Override
250+ default boolean addAll (Collection <? extends Column <T >> c ) {
251+ throw readOnlyException ();
252+ }
253+
254+ @ Override
255+ default boolean addAll (int col , Collection <? extends Column <T >> c ) {
256+ throw readOnlyException ();
257+ }
258+
259+ @ Override
260+ default boolean removeAll (Collection <?> c ) {
261+ throw readOnlyException ();
262+ }
263+
264+ @ Override
265+ default boolean retainAll (Collection <?> c ) {
266+ throw readOnlyException ();
267+ }
268+
269+ @ Override
270+ default void clear () {
271+ throw readOnlyException ();
272+ }
273+
274+ @ Override
275+ default Column <T > set (int col , Column <T > column ) {
276+ throw readOnlyException ();
277+ }
278+
279+ @ Override
280+ default void add (int col , Column <T > column ) {
281+ throw readOnlyException ();
282+ }
283+
284+ @ Override
285+ default Column <T > remove (int col ) {
286+ throw readOnlyException ();
287+ }
288+ }
289+
290+ /** Read-only version of a {@link Column}. */
291+ private static interface ReadOnlyColumn <T > extends Column <T > {
292+
293+ @ Override
294+ default boolean add (final T e ) {
295+ throw readOnlyException ();
296+ }
297+
298+ @ Override
299+ default boolean remove (Object o ) {
300+ throw readOnlyException ();
301+ }
302+
303+ @ Override
304+ default boolean addAll (Collection <? extends T > c ) {
305+ throw readOnlyException ();
306+ }
307+
308+ @ Override
309+ default boolean addAll (int index , Collection <? extends T > c ) {
310+ throw readOnlyException ();
311+ }
312+
313+ @ Override
314+ default boolean removeAll (Collection <?> c ) {
315+ throw readOnlyException ();
316+ }
317+
318+ @ Override
319+ default boolean retainAll (Collection <?> c ) {
320+ throw readOnlyException ();
321+ }
322+
323+ @ Override
324+ default void clear () {
325+ throw readOnlyException ();
326+ }
327+
328+ @ Override
329+ default T set (int index , T element ) {
330+ throw readOnlyException ();
331+ }
332+
333+ @ Override
334+ default void add (int index , T element ) {
335+ throw readOnlyException ();
336+ }
337+
338+ @ Override
339+ default T remove (int index ) {
340+ throw readOnlyException ();
341+ }
342+
343+ @ Override
344+ default void setHeader (String header ) {
345+ throw readOnlyException ();
346+ }
347+
348+ @ Override
349+ default void setSize (int size ) {
350+ throw readOnlyException ();
351+ }
352+ }
101353}
0 commit comments