##// END OF EJS Templates
Adapts sort() method to 2-dim array data (1)...
Alexandre Leroux -
r504:64f65829e732
parent child
Show More
@@ -1,39 +1,64
1 #ifndef SCIQLOP_SORTUTILS_H
1 #ifndef SCIQLOP_SORTUTILS_H
2 #define SCIQLOP_SORTUTILS_H
2 #define SCIQLOP_SORTUTILS_H
3
3
4 #include <algorithm>
4 #include <algorithm>
5 #include <numeric>
5 #include <numeric>
6 #include <vector>
6 #include <vector>
7
7
8 /**
8 /**
9 * Utility class with methods for sorting data
9 * Utility class with methods for sorting data
10 */
10 */
11 struct SortUtils {
11 struct SortUtils {
12 /**
12 /**
13 * Generates a vector representing the index of insertion of each data of a container if this
13 * Generates a vector representing the index of insertion of each data of a container if this
14 * one had to be sorted according to a comparison function.
14 * one had to be sorted according to a comparison function.
15 *
15 *
16 * For example:
16 * For example:
17 * If the container is a vector {1; 4; 2; 5; 3} and the comparison function is std::less, the
17 * If the container is a vector {1; 4; 2; 5; 3} and the comparison function is std::less, the
18 * result would be : {0; 3; 1; 4; 2}
18 * result would be : {0; 3; 1; 4; 2}
19 *
19 *
20 * @tparam Container the type of the container.
20 * @tparam Container the type of the container.
21 * @tparam Compare the type of the comparison function
21 * @tparam Compare the type of the comparison function
22 * @param container the container from which to generate the result. The container must have a
22 * @param container the container from which to generate the result. The container must have a
23 * at() method that returns a value associated to an index
23 * at() method that returns a value associated to an index
24 * @param compare the comparison function
24 * @param compare the comparison function
25 */
25 */
26 template <typename Container, typename Compare>
26 template <typename Container, typename Compare>
27 static std::vector<int> sortPermutation(const Container &container, const Compare &compare)
27 static std::vector<int> sortPermutation(const Container &container, const Compare &compare)
28 {
28 {
29 auto permutation = std::vector<int>{};
29 auto permutation = std::vector<int>{};
30 permutation.resize(container.size());
30 permutation.resize(container.size());
31
31
32 std::iota(permutation.begin(), permutation.end(), 0);
32 std::iota(permutation.begin(), permutation.end(), 0);
33 std::sort(permutation.begin(), permutation.end(),
33 std::sort(permutation.begin(), permutation.end(),
34 [&](int i, int j) { return compare(container.at(i), container.at(j)); });
34 [&](int i, int j) { return compare(container.at(i), container.at(j)); });
35 return permutation;
35 return permutation;
36 }
36 }
37
38 /**
39 * Sorts a container according to indices passed in parameter
40 * @param container the container sorted
41 * @param sortPermutation the indices used to sort the container
42 * @return the container sorted
43 * @warning no verification is made on validity of sortPermutation (i.e. the vector has unique
44 * indices and its range is [0 ; vector.size()[ )
45 */
46 template <typename Container>
47 static Container sort(const Container &container, const std::vector<int> &sortPermutation)
48 {
49 if (container.size() != sortPermutation.size()) {
50 return Container{};
51 }
52
53 // Inits result
54 auto sortedData = Container{};
55 sortedData.resize(container.size());
56
57 std::transform(sortPermutation.cbegin(), sortPermutation.cend(), sortedData.begin(),
58 [&container](int i) { return container.at(i); });
59
60 return sortedData;
61 }
37 };
62 };
38
63
39 #endif // SCIQLOP_SORTUTILS_H
64 #endif // SCIQLOP_SORTUTILS_H
@@ -1,174 +1,166
1 #ifndef SCIQLOP_ARRAYDATA_H
1 #ifndef SCIQLOP_ARRAYDATA_H
2 #define SCIQLOP_ARRAYDATA_H
2 #define SCIQLOP_ARRAYDATA_H
3
3
4 #include <Common/SortUtils.h>
5
4 #include <QReadLocker>
6 #include <QReadLocker>
5 #include <QReadWriteLock>
7 #include <QReadWriteLock>
6 #include <QVector>
8 #include <QVector>
7
9
8 #include <memory>
10 #include <memory>
9
11
10 /**
12 /**
11 * @brief The ArrayData class represents a dataset for a data series.
13 * @brief The ArrayData class represents a dataset for a data series.
12 *
14 *
13 * A dataset can be unidimensional or two-dimensional. This property is determined by the Dim
15 * A dataset can be unidimensional or two-dimensional. This property is determined by the Dim
14 * template-parameter. In a case of a two-dimensional dataset, each dataset component has the same
16 * template-parameter. In a case of a two-dimensional dataset, each dataset component has the same
15 * number of values
17 * number of values
16 *
18 *
17 * @tparam Dim the dimension of the ArrayData (one or two)
19 * @tparam Dim the dimension of the ArrayData (one or two)
18 * @sa IDataSeries
20 * @sa IDataSeries
19 */
21 */
20 template <int Dim>
22 template <int Dim>
21 class ArrayData {
23 class ArrayData {
22 public:
24 public:
23 /**
25 /**
24 * Ctor for a unidimensional ArrayData
26 * Ctor for a unidimensional ArrayData
25 * @param data the data the ArrayData will hold
27 * @param data the data the ArrayData will hold
26 */
28 */
27 template <int D = Dim, typename = std::enable_if_t<D == 1> >
29 template <int D = Dim, typename = std::enable_if_t<D == 1> >
28 explicit ArrayData(QVector<double> data) : m_Data{1, QVector<double>{}}
30 explicit ArrayData(QVector<double> data) : m_Data{1, QVector<double>{}}
29 {
31 {
30 m_Data[0] = std::move(data);
32 m_Data[0] = std::move(data);
31 }
33 }
32
34
33 /**
35 /**
34 * Ctor for a two-dimensional ArrayData. The number of components (number of vectors) must be
36 * Ctor for a two-dimensional ArrayData. The number of components (number of vectors) must be
35 * greater than 2 and each component must have the same number of values
37 * greater than 2 and each component must have the same number of values
36 * @param data the data the ArrayData will hold
38 * @param data the data the ArrayData will hold
37 * @throws std::invalid_argument if the number of components is less than 2
39 * @throws std::invalid_argument if the number of components is less than 2
38 * @remarks if the number of values is not the same for each component, no value is set
40 * @remarks if the number of values is not the same for each component, no value is set
39 */
41 */
40 template <int D = Dim, typename = std::enable_if_t<D == 2> >
42 template <int D = Dim, typename = std::enable_if_t<D == 2> >
41 explicit ArrayData(QVector<QVector<double> > data)
43 explicit ArrayData(QVector<QVector<double> > data)
42 {
44 {
43 auto nbComponents = data.size();
45 auto nbComponents = data.size();
44 if (nbComponents < 2) {
46 if (nbComponents < 2) {
45 throw std::invalid_argument{
47 throw std::invalid_argument{
46 QString{"A multidimensional ArrayData must have at least 2 components (found: %1"}
48 QString{"A multidimensional ArrayData must have at least 2 components (found: %1"}
47 .arg(data.size())
49 .arg(data.size())
48 .toStdString()};
50 .toStdString()};
49 }
51 }
50
52
51 auto nbValues = data.front().size();
53 auto nbValues = data.front().size();
52 if (std::all_of(data.cbegin(), data.cend(), [nbValues](const auto &component) {
54 if (std::all_of(data.cbegin(), data.cend(), [nbValues](const auto &component) {
53 return component.size() == nbValues;
55 return component.size() == nbValues;
54 })) {
56 })) {
55 m_Data = std::move(data);
57 m_Data = std::move(data);
56 }
58 }
57 else {
59 else {
58 m_Data = QVector<QVector<double> >{nbComponents, QVector<double>{}};
60 m_Data = QVector<QVector<double> >{nbComponents, QVector<double>{}};
59 }
61 }
60 }
62 }
61
63
62 /// Copy ctor
64 /// Copy ctor
63 explicit ArrayData(const ArrayData &other)
65 explicit ArrayData(const ArrayData &other)
64 {
66 {
65 QReadLocker otherLocker{&other.m_Lock};
67 QReadLocker otherLocker{&other.m_Lock};
66 m_Data = other.m_Data;
68 m_Data = other.m_Data;
67 }
69 }
68
70
69 /**
71 /**
70 * @return the data at a specified index
72 * @return the data at a specified index
71 * @remarks index must be a valid position
73 * @remarks index must be a valid position
72 * @remarks this method is only available for a unidimensional ArrayData
74 * @remarks this method is only available for a unidimensional ArrayData
73 */
75 */
74 template <int D = Dim, typename = std::enable_if_t<D == 1> >
76 template <int D = Dim, typename = std::enable_if_t<D == 1> >
75 double at(int index) const noexcept
77 double at(int index) const noexcept
76 {
78 {
77 QReadLocker locker{&m_Lock};
79 QReadLocker locker{&m_Lock};
78 return m_Data[0].at(index);
80 return m_Data[0].at(index);
79 }
81 }
80
82
81 /**
83 /**
82 * @return the data as a vector
84 * @return the data as a vector
83 * @remarks this method is only available for a unidimensional ArrayData
85 * @remarks this method is only available for a unidimensional ArrayData
84 */
86 */
85 template <int D = Dim, typename = std::enable_if_t<D == 1> >
87 template <int D = Dim, typename = std::enable_if_t<D == 1> >
86 QVector<double> data() const noexcept
88 QVector<double> data() const noexcept
87 {
89 {
88 QReadLocker locker{&m_Lock};
90 QReadLocker locker{&m_Lock};
89 return m_Data[0];
91 return m_Data[0];
90 }
92 }
91
93
92 /**
94 /**
93 * @return the data as a vector, as a const reference
95 * @return the data as a vector, as a const reference
94 * @remarks this method is only available for a unidimensional ArrayData
96 * @remarks this method is only available for a unidimensional ArrayData
95 */
97 */
96 template <int D = Dim, typename = std::enable_if_t<D == 1> >
98 template <int D = Dim, typename = std::enable_if_t<D == 1> >
97 const QVector<double> &cdata() const noexcept
99 const QVector<double> &cdata() const noexcept
98 {
100 {
99 QReadLocker locker{&m_Lock};
101 QReadLocker locker{&m_Lock};
100 return m_Data.at(0);
102 return m_Data.at(0);
101 }
103 }
102
104
103 /**
105 /**
104 * Merges into the array data an other array data
106 * Merges into the array data an other array data
105 * @param other the array data to merge with
107 * @param other the array data to merge with
106 * @param prepend if true, the other array data is inserted at the beginning, otherwise it is
108 * @param prepend if true, the other array data is inserted at the beginning, otherwise it is
107 * inserted at the end
109 * inserted at the end
108 * @remarks this method is only available for a unidimensional ArrayData
110 * @remarks this method is only available for a unidimensional ArrayData
109 */
111 */
110 template <int D = Dim, typename = std::enable_if_t<D == 1> >
112 template <int D = Dim, typename = std::enable_if_t<D == 1> >
111 void add(const ArrayData<1> &other, bool prepend = false)
113 void add(const ArrayData<1> &other, bool prepend = false)
112 {
114 {
113 QWriteLocker locker{&m_Lock};
115 QWriteLocker locker{&m_Lock};
114 if (!m_Data.empty()) {
116 if (!m_Data.empty()) {
115 QReadLocker otherLocker{&other.m_Lock};
117 QReadLocker otherLocker{&other.m_Lock};
116
118
117 if (prepend) {
119 if (prepend) {
118 const auto &otherData = other.data();
120 const auto &otherData = other.data();
119 const auto otherDataSize = otherData.size();
121 const auto otherDataSize = otherData.size();
120
122
121 auto &data = m_Data[0];
123 auto &data = m_Data[0];
122 data.insert(data.begin(), otherDataSize, 0.);
124 data.insert(data.begin(), otherDataSize, 0.);
123
125
124 for (auto i = 0; i < otherDataSize; ++i) {
126 for (auto i = 0; i < otherDataSize; ++i) {
125 data.replace(i, otherData.at(i));
127 data.replace(i, otherData.at(i));
126 }
128 }
127 }
129 }
128 else {
130 else {
129 m_Data[0] += other.data();
131 m_Data[0] += other.data();
130 }
132 }
131 }
133 }
132 }
134 }
133
135
134 /// @return the size (i.e. number of values) of a single component
136 /// @return the size (i.e. number of values) of a single component
135 /// @remarks in a case of a two-dimensional ArrayData, each component has the same size
137 /// @remarks in a case of a two-dimensional ArrayData, each component has the same size
136 int size() const
138 int size() const
137 {
139 {
138 QReadLocker locker{&m_Lock};
140 QReadLocker locker{&m_Lock};
139 return m_Data[0].size();
141 return m_Data[0].size();
140 }
142 }
141
143
142 template <int D = Dim, typename = std::enable_if_t<D == 1> >
144 template <int D = Dim, typename = std::enable_if_t<D == 1> >
143 std::shared_ptr<ArrayData<Dim> > sort(const std::vector<int> sortPermutation)
145 std::shared_ptr<ArrayData<Dim> > sort(const std::vector<int> &sortPermutation)
144 {
146 {
145 QReadLocker locker{&m_Lock};
147 QReadLocker locker{&m_Lock};
146
148 return std::make_shared<ArrayData<Dim> >(SortUtils::sort(m_Data.at(0), sortPermutation));
147 const auto &data = m_Data.at(0);
148
149 // Inits result
150 auto sortedData = QVector<double>{};
151 sortedData.resize(data.size());
152
153 std::transform(sortPermutation.cbegin(), sortPermutation.cend(), sortedData.begin(),
154 [&data](int i) { return data[i]; });
155
156 return std::make_shared<ArrayData<Dim> >(std::move(sortedData));
157 }
149 }
158
150
159 void clear()
151 void clear()
160 {
152 {
161 QWriteLocker locker{&m_Lock};
153 QWriteLocker locker{&m_Lock};
162
154
163 auto nbComponents = m_Data.size();
155 auto nbComponents = m_Data.size();
164 for (auto i = 0; i < nbComponents; ++i) {
156 for (auto i = 0; i < nbComponents; ++i) {
165 m_Data[i].clear();
157 m_Data[i].clear();
166 }
158 }
167 }
159 }
168
160
169 private:
161 private:
170 QVector<QVector<double> > m_Data;
162 QVector<QVector<double> > m_Data;
171 mutable QReadWriteLock m_Lock;
163 mutable QReadWriteLock m_Lock;
172 };
164 };
173
165
174 #endif // SCIQLOP_ARRAYDATA_H
166 #endif // SCIQLOP_ARRAYDATA_H
General Comments 0
You need to be logged in to leave comments. Login now