2015-07-16 14 views
10

Trong dự án hiện tại của tôi, tôi đang xử lý một cơ sở dữ liệu đa chiều. Tệp cơ bản được lưu trữ tuần tự (nghĩa là một mảng lớn, không có vec-tơ vectơ). Các thuật toán sử dụng các datastructures cần phải biết kích thước của các kích thước cá nhân.Trình biến đổi đa chiều chung C++

Tôi tự hỏi liệu một lớp lặp đa chiều đã được xác định một nơi nào đó theo cách chung chung và nếu có bất kỳ tiêu chuẩn hay cách thức ưu tiên nào về cách giải quyết vấn đề này.

Hiện tại tôi chỉ đang sử dụng trình lặp vòng tuyến tính với một số phương thức bổ sung trả về kích thước của từng thứ nguyên và số lượng thứ nguyên có trong phần đầu tiên. Lý do tôi không thích nó là bởi vì tôi không thể sử dụng std :: khoảng cách một cách hợp lý ví dụ (tức là chỉ trả về khoảng cách của toàn bộ cấu trúc, nhưng không thể cho từng kích thước riêng biệt).

Đối với hầu hết các phần, tôi sẽ truy cập vào cơ sở hạ tầng theo kiểu tuyến tính (thứ nguyên đầu tiên bắt đầu hoàn thành -> thứ nguyên tiếp theo + ... vv), nhưng sẽ rất tốt khi biết khi một thứ nguyên "kết thúc". Tôi không biết làm thế nào để làm điều này chỉ với toán tử *(), toán tử +() và toán tử ==() trong cách tiếp cận như vậy.

Một vector của phương pháp tiếp cận vectơ bị phản đối vì tôi không muốn chia nhỏ tệp. Ngoài ra các thuật toán phải hoạt động trên cấu trúc với chiều khác nhau và do đó khó để khái quát (hoặc có thể có một cách?).

Tăng multi_array có cùng vấn đề (nhiều "cấp" của trình lặp).

Tôi hy vọng điều này không quá mơ hồ hoặc trừu tượng. Bất kỳ gợi ý nào về đúng hướng sẽ được đánh giá cao.

Tôi đang tìm kiếm giải pháp cho bản thân mình một lần nữa và xem xét lại tăng :: multi_array. Khi nó quay ra có thể tạo ra các quan điểm phụ trên dữ liệu với chúng, nhưng đồng thời cũng có một trình lặp trực tiếp ở cấp cao nhất và ngầm "làm phẳng" cấu trúc dữ liệu. Các phiên bản thực hiện của multi_array tuy nhiên không phù hợp với nhu cầu của tôi, do đó tôi có thể sẽ thực hiện một bản thân (xử lý bộ nhớ đệm của các tệp trong nền) tương thích với các multi_arrays khác.

Tôi sẽ cập nhật lại sau khi triển khai xong.

+1

Dường như bạn phải tự thực hiện trình lặp lặp nhiều chiều. Chỉ cần không giới hạn mình với các toán tử: bạn có thể sử dụng các phương thức được đặt tên để truy vấn thông tin về vị trí hiện tại trong mỗi thứ nguyên. –

+2

Câu hỏi này rất thú vị. Cách duy nhất tôi tìm thấy để cung cấp thông tin như vậy là có các phương pháp có thể suy ra chỉ số đa, ví dụ: '{x, y, z}' từ chỉ số flatten (và ngược lại). Tôi không thấy làm thế nào bạn có thể làm điều đó một cách "tiêu chuẩn" mà không cung cấp lớp tùy chỉnh của riêng bạn cho mục đích đó. – coincoin

+0

Cảm ơn cả hai về câu trả lời nhanh. @SergeRogatch: Đó là những gì tôi cũng nghĩ, nhưng nó có vẻ như vậy "chống thành ngữ". – Lazarus535

Trả lời

2

Tôi vừa quyết định mở một kho lưu trữ công khai trên Github: MultiDim Grid có thể giúp cho nhu cầu của bạn. Đây là một dự án đang diễn ra để Tôi sẽ vui mừng nếu bạn có thể thử nó và cho tôi biết những gì bạn bỏ lỡ/cần.

Tôi đã bắt đầu thực hiện việc này với điều này topic trên codereview.

Đặt nó chỉ đơn giản là:

MultiDim Lưới đề xuất một mảng uni chiều phẳng trong đó cung cấp một chung giữa tọa độ đa chiều truy cập nhanh và flatten chỉ mục.

Bạn nhận được hành vi vùng chứa để bạn có quyền truy cập vào trình lặp.

+0

Cảm ơn (cả hai) cho các câu trả lời và sry cho chỉ phản ứng quá muộn ... bận rộn. Bởi bây giờ tôi đã triển khai thực hiện riêng của tôi, mà không phải là không giống với dự án của bạn và tôi hạnh phúc với nó cho đến nay. Tôi đã không chạm vào mã đó trong một thời gian dài, bởi vì nó chỉ làm những gì tôi muốn nó làm, nhưng nếu tôi làm lại, tôi kiểm tra mã của bạn và có thể kết hợp các lực lượng. – Lazarus535

1

Điều đó không khó thực hiện. Chỉ cần nêu chính xác chức năng mà dự án của bạn yêu cầu. Đây là một mẫu câm.

#include <iostream> 
#include <array> 
#include <vector> 
#include <cassert> 

template<typename T, int dim> 
class DimVector : public std::vector<T> { 
public: 
    DimVector() { 
     clear(); 
    } 

    void clear() { 
     for (auto& i : _sizes) 
      i = 0; 
     std::vector<T>::clear(); 
    } 

    template<class ... Types> 
    void resize(Types ... args) { 
     std::array<int, dim> new_sizes = { args ... }; 
     resize(new_sizes); 
    } 

    void resize(std::array<int, dim> new_sizes) { 
     clear(); 
     for (int i = 0; i < dim; ++i) 
      if (new_sizes[i] == 0) 
       return; 
     _sizes = new_sizes; 
     int realsize = _sizes[0]; 
     for (int i = 1; i < dim; ++i) 
      realsize *= _sizes[i]; 
     std::vector<T>::resize(static_cast<size_t>(realsize)); 
    } 

    decltype(auto) operator()(std::array<int, dim> pos) { 
     // check indexes and compute original index 
     size_t index; 
     for (int i = 0; i < dim; ++i) { 
      assert(0 <= pos[i] && pos[i] < _sizes[i]); 
      index = (i == 0) ? pos[i] : (index * _sizes[i] + pos[i]); 
     } 
     return std::vector<T>::at(index); 
    } 

    template<class ... Types> 
    decltype(auto) at(Types ... args) { 
     std::array<int, dim> pos = { args ... }; 
     return (*this)(pos); 
    } 

    int size(int d) const { 
     return _sizes[d]; 
    } 


    class Iterator { 
    public: 
     T& operator*() const; 
     T* operator->() const; 
     bool operator!=(const Iterator& other) const { 
      if (&_vec != &other._vec) 
       return true; 
      for (int i = 0; i < dim; ++i) 
       if (_pos[i] != other._pos[i]) 
        return true; 
      return false; 
     } 
     int get_dim(int d) const { 
      assert(0 <= d && d < dim); 
      return _pos[d]; 
     } 
     void add_dim(int d, int value = 1) { 
      assert(0 <= d && d < dim); 
      _pos[d] += value; 
      assert(0 <= _pos[i] && _pos[i] < _vec._sizes[i]); 
     } 
    private: 
     DimVector &_vec; 
     std::array<int, dim> _pos; 
     Iterator(DimVector& vec, std::array<int, dim> pos) : _vec(vec), _pos(pos) { } 
    }; 

    Iterator getIterator(int pos[dim]) { 
     return Iterator(*this, pos); 
    } 

private: 
    std::array<int, dim> _sizes; 
}; 

template<typename T, int dim> 
inline T& DimVector<T, dim>::Iterator::operator*() const { 
    return _vec(_pos); 
} 

template<typename T, int dim> 
inline T* DimVector<T, dim>::Iterator::operator->() const { 
    return &_vec(_pos); 
} 

using namespace std; 

int main() { 

    DimVector<int, 4> v; 
    v.resize(1, 2, 3, 4); 
    v.at(0, 0, 0, 1) = 1; 
    v.at(0, 1, 0, 0) = 1; 

    for (int w = 0; w < v.size(0); ++w) { 
     for (int z = 0; z < v.size(1); ++z) { 
      for (int y = 0; y < v.size(2); ++y) { 
       for (int x = 0; x < v.size(3); ++x) { 
        cout << v.at(w, z, y, x) << ' '; 
       } 
       cout << endl; 
      } 
      cout << "----------------------------------" << endl; 
     } 
     cout << "==================================" << endl; 
    } 
    return 0; 
} 

danh sách TODO:

  • tối ưu hóa: sử dụng T const& khi có thể
  • iterator optimizate: realindex precompute và sau đó chỉ cần thay đổi điều đó realindex
  • thực hiện const accessors
  • thực hiện ConstIterator
  • triển khai operator>>operator<< để tuần tự hóa DimVector thành/từ tệp
Các vấn đề liên quan