sort.h 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #ifndef IGL_SORT_H
  2. #define IGL_SORT_H
  3. #include <vector>
  4. namespace igl
  5. {
  6. // Sort the elements of a matrix X along a given dimension like matlabs sort
  7. // function
  8. //
  9. // Templates:
  10. // T should be a eigen matrix primitive type like int or double
  11. // Inputs:
  12. // X m by n matrix whose entries are to be sorted
  13. // dim dimensional along which to sort:
  14. // 1 sort each column (matlab default)
  15. // 2 sort each row
  16. // ascending sort ascending (true, matlab default) or descending (false)
  17. // Outputs:
  18. // Y m by n matrix whose entries are sorted
  19. // IX m by n matrix of indices so that if dim = 1, then in matlab notation
  20. // for j = 1:n, Y(:,j) = X(I(:,j),j); end
  21. template <typename T>
  22. inline void sort(
  23. const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & X,
  24. const int dim,
  25. const bool ascending,
  26. Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & Y,
  27. Eigen::MatrixXi & IX);
  28. // Act like matlab's [Y,I] = SORT(X) for std library vectors
  29. // Templates:
  30. // T should be a class that implements the '<' comparator operator
  31. // Input:
  32. // unsorted unsorted vector
  33. // ascending sort ascending (true, matlab default) or descending (false)
  34. // Output:
  35. // sorted sorted vector, allowed to be same as unsorted
  36. // index_map an index map such that sorted[i] = unsorted[index_map[i]]
  37. template <class T>
  38. inline void sort(
  39. const std::vector<T> &unsorted,
  40. const bool ascending,
  41. std::vector<T> &sorted,
  42. std::vector<size_t> &index_map);
  43. }
  44. // Implementation
  45. #include <algorithm>
  46. #include "reorder.h"
  47. template <typename T>
  48. inline void igl::sort(
  49. const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & X,
  50. const int dim,
  51. const bool ascending,
  52. Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & Y,
  53. Eigen::MatrixXi & IX)
  54. {
  55. // dim must be 2 or 1
  56. assert(dim == 1 || dim == 2);
  57. // Resize output
  58. Y.resize(X.rows(),X.cols());
  59. IX.resize(X.rows(),X.cols());
  60. // idea is to process each column (or row) as a std vector
  61. // get number of columns (or rows)
  62. int num_outer = (dim == 1 ? X.cols() : X.rows() );
  63. // get number of rows (or columns)
  64. int num_inner = (dim == 1 ? X.rows() : X.cols() );
  65. // loop over columns (or rows)
  66. for(int i = 0; i<num_outer;i++)
  67. {
  68. // Unsorted index map for this column (or row)
  69. std::vector<size_t> index_map(num_inner);
  70. std::vector<T> data(num_inner);
  71. for(int j = 0;j<num_inner;j++)
  72. {
  73. if(dim == 1)
  74. {
  75. data[j] = X(j,i);
  76. }else
  77. {
  78. data[j] = X(i,j);
  79. }
  80. }
  81. // sort this column (or row)
  82. sort<T>(
  83. data,
  84. ascending,
  85. data,
  86. index_map);
  87. // Copy into Y and IX
  88. for(int j = 0;j<num_inner;j++)
  89. {
  90. if(dim == 1)
  91. {
  92. Y(j,i) = data[j];
  93. IX(j,i) = index_map[j];
  94. }else
  95. {
  96. Y(i,j) = data[j];
  97. IX(i,j) = index_map[j];
  98. }
  99. }
  100. }
  101. }
  102. // Comparison struct used by sort
  103. // http://bytes.com/topic/c/answers/132045-sort-get-index
  104. template<class T> struct index_cmp
  105. {
  106. index_cmp(const T arr) : arr(arr) {}
  107. bool operator()(const size_t a, const size_t b) const
  108. {
  109. return arr[a] < arr[b];
  110. }
  111. const T arr;
  112. };
  113. template <class T>
  114. inline void igl::sort(
  115. const std::vector<T> & unsorted,
  116. const bool ascending,
  117. std::vector<T> & sorted,
  118. std::vector<size_t> & index_map)
  119. {
  120. // Original unsorted index map
  121. index_map.resize(unsorted.size());
  122. for(size_t i=0;i<unsorted.size();i++)
  123. {
  124. index_map[i] = i;
  125. }
  126. // Sort the index map, using unsorted for comparison
  127. sort(
  128. index_map.begin(),
  129. index_map.end(),
  130. index_cmp<const std::vector<T>& >(unsorted));
  131. // if not ascending then reverse
  132. if(!ascending)
  133. {
  134. std::reverse(index_map.begin(),index_map.end());
  135. }
  136. // make space for output without clobbering
  137. sorted.resize(unsorted.size());
  138. // reorder unsorted into sorted using index map
  139. igl::reorder(unsorted,index_map,sorted);
  140. }
  141. #endif