-
Notifications
You must be signed in to change notification settings - Fork 3
Data::StaticTable
A StaticTable allows you to handle bidimensional data in a more natural way
Some features:
- Rows starts at 1 (
Data::StaticTable::Position
is the datatype used to reference row numbers) - Columns have header names
- Any column can work as an index
If the number of elements provided does not suffice to form a square or a rectangle, filler cells will be added as filler. (you can define what goes in these filler cells too)
The module provides two classes: StaticTable
and StaticTable::Query
.
A StaticTable can be populated, but it can not be modified later. To perform searchs and create/store indexes, a Query object is provided. You can add indexes per column, and perform searches (grep) later. If an index exists, it will be used.
You can get data by rows, columns, and create subsets by taking some rows from an existing StaticTable.
Basically, an integer greater than 0. Used to indicate a row position in the table. A StaticTable do not have rows on index 0.
Compares the contents (header and data) of two StaticTable objects. Returns False
as soon as any difference is detected, and True
if finds that everything is equal.
say '$t1 and $t2 are ' ~ ($t1 eqv $t2) ?? 'equal' !! 'different';
You can use [n] to get the full Nth row, in the way of a hash of 'Column name' => data
So, for example
$t[1]
Could return a hash like
{Column1 => 10, Column2 => 200.4, Column3 => 450}
And a call like
$t[10]<Column3>
would refer to the data in Row 10, with the heading Column3
On construction, a public hash called ci
(short for column index) is created. If for some reason, you need to refer the columns by number instead of name, this hash contains the column numbers as keys, and the heading name as values.
if your column number 2 has the name "Weight", you can read the cell in the third row of that column like this:
my $val1 = $t.cell('Weight', 3);
my $val2 = $t[3]<Weight>;
Or by using the ci
hash
my $val1 = $t.cell($t.ci<2>, 3);
my $val2 = $t[3]{$t.ci<2>};
The table has a public member that contains the header in the shape of an array.
my @column_names = $t1.header;
Depending on how your source data is organized, you can use the 2 flat array constructors or a rowset constructor.
Flat array allows you to pass a long one dimensional array and order it in rows and columns, by specifiying a header. You can pass an array of string to specify the column names, or just a number of columns if you don't care about the column names.
Rowset works when your data is already bidimensional, and it can include a first row as header. In the case that your rows contains a hash, you can tell the constructor, and it will take the hash keys to create a header with the appropiate column names. In this case, any row that does not contain a hash will be discarded (You have the option to recover the discarded data).
my $t1 = StaticTable.new( 3 , (1 .. 15) );
my $t2 = StaticTable.new(
<Column1 Column2 Column3> ,
(
1, 2, 3,
4, 5, 6,
7, 8, 9,
10,11,12
13,14,15
)
);
This will create a spreadsheet-like table, with numbered rows and labeled columns.
In the case of $t1
, since the first parameter is a number, it will have columns named automatically, as A
, B
, C
... etc.
$t2
has an array as the first parameter. So it will have three columns labeled Column1
, Column2
and Column3
.
You just need to provide an array to fill the table. The rows and columns will be automatically cut and filled in a number of rows.
If you do not provide enough data to fill the last row, empty cells will be appended.
If you already have your data ordered in an array of arrays, use the rowset constructor described below.
You can also create a StaticTable from an array, with each element representing a row. The StaticTable will acommodate the values as best as possible, adding empty values or discarding values that go beyond the boundaries, or data that is not prepared appropiately
This constructor can be called like this, using an Array of Arrays
my $t = StaticTable.new(
(1,2,3),
(4,5,6),
(7,8,9)
);
For a Array of Hashes, you can call it like this
my $t = StaticTable.new(
[
{ name => 'Eggplant', color => 'aubergine', type => 'vegetal' },
{ name => 'Egg', color => ('white', 'beige'), type => 'animal' },
{ name => 'Banana', color => 'yellow', type => 'fruit' },
{ name => 'Avocado', color => 'green', type => 'fruit', class => 'Hass' }
]
);
(Note the use of brackets, we needed to explicitly pass an Array of Hashes)
There is a set of named parameters usable in this constructor
my $t = StaticTable.new(@ArrayOfArrays):data-has-header
This will use the first row as header. Any value that falls outside the column boundaries determined by the header will be discarded in each row.
my $t = StaticTable.new(@ArrayOfHashes):set-of-hashes
This will consider each row as a hash, and will create columns for each key found. The most populated will be the first columns. Any row that is not a hash will be discarded
In some situations, some data can be rejected from your original array passed to the constructor. This will happen in two cases, using the rowset constructor:
- You specified
:data-has-header
but there are rows longer that the lenght of the header. So, if your first row had 4 elements, any row with more that 4 elements will be cut and the extra elements will be rejected - You specified
:set-of-hashes
but there are rows that does not contain hashes. All these rows will be rejected too.
For recovering discarded data from an Array of Arrays:
my %rejected;
my $tAoA = StaticTable.new(
@ArrayOfArrays, rejected-data => %rejected # <--- Note, rejected is a hash
):data-has-header
In this case, %rejected
is a hash where the key is the row from where the data was discarded, pointing to an array of the elements discarded in that row.
For recovering discarded data from an Array of Hashes:
my @rejected;
my $tAoH = StaticTable.new(
@ArrayOfHashes, rejected-data => @rejected # <--- rejected is an array
):set-of-hashes
In this case, @rejected
will have a list of all the rejected rows.
There is another named parameter, called filler
. This is used to complete rows that needs more cells, so the table has every row with the same number of elements.
By default, it uses Nil
.
Example:
my $t = Data::StaticTable.new(
<A B C>,
(1,2,3,
4,5,6,
7), # 2 last cells will be fillers, so the 3rd row is complete
filler => 'N/A'
);
print $t[3]<C>; #This will print N/A
Returns a representation of the StaticTable. Can be used for serialization.
Returns a newly created StaticTable with the same attributes. It does not copy attributes to clone. Instead, runs the constructor again.
Shows a 'visual' representation of the contents of the StaticTable. Used for debugging, not for serialization.
It would look like this:
A B C
- - -
[1] [2] [3]
[4] [5] [6]
[7] [8] [9]
However, you could save the output of this method to a tab-separated csv file.
Retrieves the content of a cell.
Retrieves the content of a column like a regular List
.
Retrieves the content of a row as a regular List
.
Retrieves the content of the table as a multiple dimension array.
Retrieves the number of cells in the table
Generate a Hash
, where the key is the value of the cell, and the value is a list of row numbers (of type Data::StaticTable::Position
).
Generate a new StaticTable
, using a list of row numbers (using the type Data::StaticTable::Position
)
The order of the rows will be kept, and you can consider repeated rows. You can use .uniq and .sort on the row numbers list. A sorted, unique list will make the construction of the new table faster. Consider this is you want to use a lot of rownums.
#-- Order and repeated rows will be kept
my $new-t1 = $t.take(@list);
#-- Consider this if @list is big, not sorted and has repeated elements
my $new-t2 = $t.take(@list.uniq.sort)
You can combine this with generate-index
my %i-Status = $t.generate-index("Status");
# We want a new table with rows where Status = "Open"
my $t-open = $t.take(%i-Status<Open>);
# We want another where Status = "Awaiting feedback"
my $t-waiting = $t.take(%i-Status{'Awaiting feedback'});
Also works with the grep
method from the StaticTable::Query
object. This allows to you do more complex searches in the columns.
An identical, but slurpy version of this method is also available for convenience.