Skip to content

Commit

Permalink
append_series() and prepend_series()
Browse files Browse the repository at this point in the history
Also added some docs for append_column() and prepend_column().

My reasoning for calling these append_series() rather than making them
overloads of append_column() is that unlike append_column() which is
mostly a frame-internal operation, append_series() is adding an actual
series<T> object that the user has access to.
  • Loading branch information
tedmiddleton committed Apr 26, 2023
1 parent 4cc2242 commit b508024
Show file tree
Hide file tree
Showing 7 changed files with 283 additions and 0 deletions.
1 change: 1 addition & 0 deletions mainframe/detail/series_vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class iseries_vector
virtual ~iseries_vector() = default;

virtual size_t size() const = 0;
virtual void resize(size_t n) = 0;
virtual bool empty() const = 0;
virtual size_t max_size() const = 0;
virtual size_t capacity() const = 0;
Expand Down
18 changes: 18 additions & 0 deletions mainframe/detail/uframe.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class uframe
append_column(const useries& s)
{
m_columns.push_back(s);
expand_consistent();
}

template<typename T>
Expand Down Expand Up @@ -103,6 +104,7 @@ class uframe
prepend_column(const useries& s)
{
m_columns.insert(m_columns.begin(), s);
expand_consistent();
}

template<typename T>
Expand All @@ -125,6 +127,7 @@ class uframe
set_column(size_t idx, const useries& s)
{
m_columns.at(idx) = s;
expand_consistent();
}

size_t
Expand Down Expand Up @@ -155,6 +158,21 @@ class uframe
}
}

void
expand_consistent()
{
if (m_columns.size() == 0) {
return;
}
size_t sz = 0U;
for (auto& s : m_columns) {
sz = std::max(sz, s.size());
}
for (auto& s : m_columns) {
s.resize(sz);
}
}

std::vector<useries> m_columns;
};

Expand Down
6 changes: 6 additions & 0 deletions mainframe/detail/useries.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ class useries
return m_name;
}

void
resize(size_t n)
{
m_data->resize(n);
}

void
set_name(const std::string& name)
{
Expand Down
80 changes: 80 additions & 0 deletions mainframe/frame.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,21 @@ class frame
frame_with_all_missing_columns
allow_missing() const;

/// Add a new column to the end of the frame with type T
///
/// frame<year_month, int> f1;
/// f1.set_column_names({"month", "length"});
/// f1.push_back(2022_y/1, 1);
/// f1.push_back(2022_y/2, 2);
/// f1.push_back(2022_y/3, 3);
/// frame<year_month, int, double> f2 = f1.append_column<double>("depth");
/// // f2 is now
/// // | month | length | depth
/// // __|_________|________|_______
/// // 0| 2022-01 | 1 | 0.0
/// // 1| 2022-02 | 2 | 0.0
/// // 2| 2022-03 | 3 | 0.0
///
template<typename T>
frame<Ts..., T>
append_column(const std::string& column_name) const;
Expand All @@ -202,6 +217,31 @@ class frame
frame<Ts..., T>
append_column(const std::string& column_name, Ex expr) const;

/// Add an existing series to the frame as a column to the end of the frame
///
/// frame<year_month, int> f1;
/// f1.set_column_names({"month", "length"});
/// f1.push_back(2022_y/1, 1);
/// f1.push_back(2022_y/2, 2);
/// f1.push_back(2022_y/3, 3);
/// series<double> s1 = {1.1, 2.2};
/// s1.set_name("depth");
/// series<double> s2 = {3.3, 4.4, 5.5, 6.6};
/// s2.set_name("height");
/// frame<year_month, int, double> f2 = f1.append_series(s1);
/// frame<year_month, int, double, double> f3 = f1.append_series(s2);
/// // f3 is now
/// // | month | length | depth | height
/// // __|_________|________|_______|________
/// // 0| 2022-01 | 1 | 1.1 | 3.3
/// // 1| 2022-02 | 2 | 2.2 | 4.4
/// // 2| 2022-03 | 3 | 0.0 | 5.5
/// // 3| 0000-00 | 0 | 0.0 | 6.6
///
template<typename T>
frame<Ts..., T>
append_series(const series<T>& s) const;

/// Remove all rows/data from the dataframe
///
void
Expand Down Expand Up @@ -384,6 +424,21 @@ class frame
void
pop_back();

/// Add a new column to the beginning of the frame with type T
///
/// frame<year_month, int> f1;
/// f1.set_column_names({"month", "length"});
/// f1.push_back(2022_y/1, 1);
/// f1.push_back(2022_y/2, 2);
/// f1.push_back(2022_y/3, 3);
/// frame<double, year_month, int> f2 = f1.prepend_column<double>("depth");
/// // f2 is now
/// // | depth | month | length
/// // __|_______|_________|________
/// // 0| 0.0 | 2022-01 | 1
/// // 1| 0.0 | 2022-02 | 2
/// // 2| 0.0 | 2022-03 | 3
///
template<typename T>
frame<T, Ts...>
prepend_column(const std::string& column_name) const;
Expand All @@ -392,6 +447,31 @@ class frame
frame<T, Ts...>
prepend_column(const std::string& column_name, Ex expr) const;

/// Add an existing series to the frame as a column to the beginning of the frame
///
/// frame<year_month, int> f1;
/// f1.set_column_names({"month", "length"});
/// f1.push_back(2022_y/1, 1);
/// f1.push_back(2022_y/2, 2);
/// f1.push_back(2022_y/3, 3);
/// series<double> s1 = {1.1, 2.2};
/// s1.set_name("depth");
/// series<double> s2 = {3.3, 4.4, 5.5, 6.6};
/// s2.set_name("height");
/// frame<double, year_month, int> f2 = f1.prepend_series(s1);
/// frame<double, double, year_month, int> f3 = f1.prepend_series(s2);
/// // f3 is now
/// // | height | depth | month | length
/// // __|________|_______|_________|________
/// // 0| 3.3 | 1.1 | 2022-01 | 1
/// // 1| 4.4 | 2.2 | 2022-02 | 2
/// // 2| 5.5 | 0.0 | 2022-03 | 3
/// // 3| 6.6 | 0.0 | 0000-00 | 0
///
template<typename T>
frame<T, Ts...>
prepend_series(const series<T>& s) const;

///
/// Append a row from another frame to the end of this frame.
///
Expand Down
22 changes: 22 additions & 0 deletions mainframe/impl/frame.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,17 @@ frame<Ts...>::append_column(const std::string& series_name, Ex expr) const
return out;
}

template<typename... Ts>
template<typename T>
frame<Ts..., T>
frame<Ts...>::append_series(const series<T>& s) const
{
uframe plust(*this);
useries us(s);
plust.append_column(us);
return plust;
}

template<typename... Ts>
void
frame<Ts...>::clear()
Expand Down Expand Up @@ -597,6 +608,17 @@ frame<Ts...>::prepend_column(const std::string& series_name, Ex expr) const
return out;
}

template<typename... Ts>
template<typename T>
frame<T, Ts...>
frame<Ts...>::prepend_series(const series<T>& s) const
{
uframe plust(*this);
useries us(s);
plust.prepend_column(us);
return plust;
}

template<typename... Ts>
template<bool IsConst, typename... Us, typename... Vs>
void
Expand Down
23 changes: 23 additions & 0 deletions tests/mainframe_series_test_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

#include <iostream>
#include <ostream>
#include <cmath>
#include <limits>
#include <complex>

#define CATCH_CONFIG_MAIN
#include "catch.hpp"
Expand All @@ -23,6 +26,26 @@ using namespace mf;
template<class T>
class TD;

template<typename T>
std::ostream& operator<<( std::ostream& o, const std::vector<T>& v )
{
o << "[";
unsigned i = 0;
for ( const auto& e : v ) {
if ( i++ != 0 ) { o << ","; }
o << e;
}
o << "]";
return o;
}

template<typename T>
std::ostream& operator<<( std::ostream& o, const std::complex<T>& c )
{
o << "{" << c.real() << "," << c.imag() << "}";
return o;
}

static char*
mystrdup(const char* s)
{
Expand Down
133 changes: 133 additions & 0 deletions tests/mainframe_test_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1078,6 +1078,74 @@ TEST_CASE("append_column()", "[frame]")
}
}

template<typename T>
class TD;

TEST_CASE("append_series()", "[frame]")
{
SECTION("default")
{
frame<year_month_day, double, bool> f1;
f1.set_column_names("date", "temperature", "rain");
f1.push_back(2022_y / January / 2, 10.0, false);
f1.push_back(2022_y / January / 3, 11.1, true);
f1.push_back(2022_y / January / 4, 12.2, false);
f1.push_back(2022_y / January / 5, 13.3, false);
f1.push_back(2022_y / January / 6, 14.4, true);
f1.push_back(2022_y / January / 7, 15.5, false);
series<double> s1{30.0, 31.1, 32.2, 33.3, 34.4};
s1.set_name("s1");
series<int> s2{0, 1, 2, 3, 4, 5, 6};
s2.set_name("s2");

auto f2 = f1.append_series(s1);
auto f3 = f2.append_series(s2);

auto it = f3.begin();
REQUIRE((*it)[_0] == 2022_y / January / 2);
REQUIRE((*it)[_1] == 10.0);
REQUIRE((*it)[_2] == false);
REQUIRE((*it)[_3] == 30.0);
REQUIRE((*it)[_4] == 0);
it++;
REQUIRE((*it)[_0] == 2022_y / January / 3);
REQUIRE((*it)[_1] == 11.1);
REQUIRE((*it)[_2] == true);
REQUIRE((*it)[_3] == 31.1);
REQUIRE((*it)[_4] == 1);
it++;
REQUIRE((*it)[_0] == 2022_y / January / 4);
REQUIRE((*it)[_1] == 12.2);
REQUIRE((*it)[_2] == false);
REQUIRE((*it)[_3] == 32.2);
REQUIRE((*it)[_4] == 2);
it++;
REQUIRE((*it)[_0] == 2022_y / January / 5);
REQUIRE((*it)[_1] == 13.3);
REQUIRE((*it)[_2] == false);
REQUIRE((*it)[_3] == 33.3);
REQUIRE((*it)[_4] == 3);
it++;
REQUIRE((*it)[_0] == 2022_y / January / 6);
REQUIRE((*it)[_1] == 14.4);
REQUIRE((*it)[_2] == true);
REQUIRE((*it)[_3] == 34.4);
REQUIRE((*it)[_4] == 4);
it++;
REQUIRE((*it)[_0] == 2022_y / January / 7);
REQUIRE((*it)[_1] == 15.5);
REQUIRE((*it)[_2] == false);
REQUIRE((*it)[_3] == 0.0);
REQUIRE((*it)[_4] == 5);
it++;
REQUIRE((*it)[_0] == year_month_day{});
REQUIRE((*it)[_1] == 0.0);
REQUIRE((*it)[_2] == false);
REQUIRE((*it)[_3] == 0.0);
REQUIRE((*it)[_4] == 6);
}
}

TEST_CASE("prepend_column()", "[frame]")
{
SECTION("default")
Expand Down Expand Up @@ -1173,6 +1241,71 @@ TEST_CASE("prepend_column()", "[frame]")
}
}

TEST_CASE("prepend_series()", "[frame]")
{
SECTION("default")
{
frame<year_month_day, double, bool> f1;
f1.set_column_names("date", "temperature", "rain");
f1.push_back(2022_y / January / 2, 10.0, false);
f1.push_back(2022_y / January / 3, 11.1, true);
f1.push_back(2022_y / January / 4, 12.2, false);
f1.push_back(2022_y / January / 5, 13.3, false);
f1.push_back(2022_y / January / 6, 14.4, true);
f1.push_back(2022_y / January / 7, 15.5, false);
series<double> s1{30.0, 31.1, 32.2, 33.3, 34.4};
s1.set_name("s1");
series<int> s2{0, 1, 2, 3, 4, 5, 6};
s2.set_name("s2");

auto f2 = f1.prepend_series(s1);
auto f3 = f2.prepend_series(s2);

auto it = f3.begin();
REQUIRE((*it)[_0] == 0);
REQUIRE((*it)[_1] == 30.0);
REQUIRE((*it)[_2] == 2022_y / January / 2);
REQUIRE((*it)[_3] == 10.0);
REQUIRE((*it)[_4] == false);
it++;
REQUIRE((*it)[_0] == 1);
REQUIRE((*it)[_1] == 31.1);
REQUIRE((*it)[_2] == 2022_y / January / 3);
REQUIRE((*it)[_3] == 11.1);
REQUIRE((*it)[_4] == true);
it++;
REQUIRE((*it)[_0] == 2);
REQUIRE((*it)[_1] == 32.2);
REQUIRE((*it)[_2] == 2022_y / January / 4);
REQUIRE((*it)[_3] == 12.2);
REQUIRE((*it)[_4] == false);
it++;
REQUIRE((*it)[_0] == 3);
REQUIRE((*it)[_1] == 33.3);
REQUIRE((*it)[_2] == 2022_y / January / 5);
REQUIRE((*it)[_3] == 13.3);
REQUIRE((*it)[_4] == false);
it++;
REQUIRE((*it)[_0] == 4);
REQUIRE((*it)[_1] == 34.4);
REQUIRE((*it)[_2] == 2022_y / January / 6);
REQUIRE((*it)[_3] == 14.4);
REQUIRE((*it)[_4] == true);
it++;
REQUIRE((*it)[_0] == 5);
REQUIRE((*it)[_1] == 0.0);
REQUIRE((*it)[_2] == 2022_y / January / 7);
REQUIRE((*it)[_3] == 15.5);
REQUIRE((*it)[_4] == false);
it++;
REQUIRE((*it)[_0] == 6);
REQUIRE((*it)[_1] == 0.0);
REQUIRE((*it)[_2] == year_month_day{});
REQUIRE((*it)[_3] == 0.0);
REQUIRE((*it)[_4] == false);
}
}

TEST_CASE("expression fn", "[frame]")
{
frame<year_month_day, double, bool> f1;
Expand Down

0 comments on commit b508024

Please sign in to comment.