株式会社エス・スリー・フォー

<stx/algorithm>

DDJ-J 1998年5月号で紹介したSTL拡張コンポーネント”STX”の改版です。
初版で定義した関数のうち、使用頻度の少ないもの、
既存のアルゴリズムで簡単に置き換えられるものを除き、新たにいくつか追加しました。

for_each

template<class InputIterator1, 
           class InputIterator2,
           class BinaryFunction>
  BinaryFunction
  for_each(InputIterator1 first1, 
           InputIterator1 last1,
           InputIterator2 first2, 
           BinaryFunction f) 
  {
    while ( first1 != last1 ) {
      f(*first1,*first2);
      ++first1;
      ++first2;
    }
    return f;
  }

0 <= i < (last-first) に対し、f(*(first1+i), *(first2+i)) を行ないます。このとき f() の戻り値は棄てられます。

// sample
void f(int x, int y) {
  cout << (x*y) << endl;
}

vector<int> v;
list<int> l;
for ( int i = 1; i < 10; ++i ) {
  v.push_back(i);
  l.push_back(i);
}
// 1*1 2*2 ... 9*9 の答を出力
stx::for_each(v.begin(), v.end(), l.begin(), l.end(), f);

for_each_backward

  template<class BidirectionalIterator, 
           class UnaryFunction>
  UnaryFunction
  for_each_backward(BidirectionalIterator first, 
                    BidirectionalIterator last,
                    UnaryFunction f) 
  {
    while ( first != last ) {
      --last;
      f(*last);
    }
    return f;
  }

std::for_each(first,last,f)の逆順すなわち、

 f(*(last-1));
 f(*(last-2));
 ...
 f(*first);

を行ないます。

// sample
void f(int x, int y) {
  cout << (x*y) << endl;
}

vector<int> v;
list<int> l;
for ( int i = 1; i < 10; ++i ) {
  v.push_back(i);
  l.push_back(i);
}
// 9*9 8*8 ... 1*1の答を出力
stx::for_each_backward(v.begin(), v.end(), l.begin(), l.end(), f);

find_last

template<class InputIterator,
           class T>
  InputIterator
  find_last(InputIterator first,
            InputIterator last,
            const T&      value)
  {
    InputIterator it = first;
    while ( first != last ) {
      if ( *first == value ) {
        it = first;
      }
      ++first;
    }
    return it;
  }

first <= i < last に対し、*i == value となる最後のiを返します。該当する i が見つからないときは last を返します。※必ず(last – first)回の比較が行なわれます。

// sample
int array[] = { 0, 1, 2, 4, 5 };
int* p = stx::find_last(array, array+5, 4);
cout << (p-array) << endl; // p = &array[3]

find_last_if

template<class InputIterator,
           class UnaryPredicate>
  InputIterator
  find_last_if(InputIterator  first,
               InputIterator  last,
               UnaryPredicate pred)
  {
    InputIterator it = first;
    while ( first != last ) {
      if ( pred(*first) ) {
        it = first;
      }
      ++first;
    }
    return it;
  }

first <= i < last に対し、pred(*i) != false となる最後のiを返します。該当する i が見つからないときは last を返します。必ず (last – first) 回の比較が行なわれます。

// sample
bool gt1(int x) {
 return x > 1;
}

int array[] = { 0, 1, 2, 4, 5 };
int* p = stx::find_last_if(array, array+5, gt1);
cout << (p-array) << endl; // p = &array[2]

find_backward

template<class BidirectionalIterator,
           class T>
  BidirectionalIterator
  find_backward(BidirectionalIterator first,
                BidirectionalIterator last,
                const T&              value)
  {
    BidirectionalIterator it = last;
    while ( first != last ) {
      --last;
      if ( *last == value ) {
        return last;
      }
    }
    return it;
  }

first <= i < last に対し、*i == value となる最後のiを返します。該当する i が見つからないときは last を返します。find_last()と異なり、シーケンスを逆順(last-1からfirstに向かって)検索します。

// sample
int array[] = { 0, 1, 2, 2, 5 };
int* p = stx::find_backward(array, array+5, 2);
cout << (p-array) << endl; // p = &array[3]

find_backward_if

template<class BidirectionalIterator,
           class UnaryPredicate>
  BidirectionalIterator
  find_backward_if(BidirectionalIterator first,
                   BidirectionalIterator last,
                   UnaryPredicate        pred)
  {
    BidirectionalIterator it = last;
    while ( first != last ) {
      --last;
      if ( pred(*last) ) {
        return last;
      }
    }
    return it;
  }

first <= i < last に対し、pred(*i) != false となる最後のiを返します。該当する i が見つからないときは last を返します。find_last()と異なり、シーケンスを逆順(last-1からfirstに向かって)検索します。

// sample
bool gt1(int x) {
 return x > 1;
}

int array[] = { 0, 1, 2, 2, 5 };
int* p = stx::find_backward_if(array, array+5, gt1);
cout << (p-array) << endl; // p = &array[4]

binary_find

template<class ForwardIterator,
           class T>
  ForwardIterator
  binary_find(ForwardIterator first,
              ForwardIterator last,
              const T&        value)
  {
    ForwardIterator t = std::lower_bound(first,last,value);
    return ( t == last || value < *t ) ? last : t;
  }

ソートされたシーケンス[first,last)からvalueと等しい要素を探し、それを指すイテレータを返します。該当する要素が見つからないときは last を返します。バイナリサーチを行なうため、時間計算量は log(last – first) です。

// sample
int array[] = { 0, 1, 2, 2, 5 };
int* p = stx::binary_find(array, array+5, 2);
cout << (p-array) << endl; // p = &array[2]
template<class ForwardIterator,
           class T,
           class BinaryPredicate>
  ForwardIterator
  binary_find(ForwardIterator first,
              ForwardIterator last,
              const T&        value,
              BinaryPredicate pred)
  {
    ForwardIterator t = std::lower_bound(first,last,value,pred);
    return ( t == last || pred(value,*t) ) ? last : t;
  }

predに従ってソートされたシーケンス[first,last)からvalueと等しい要素を探し、それを指すイテレータを返します。該当する要素が見つからないときは last を返します。バイナリサーチを行なうため、時間計算量は log(last – first) です。

// sample
int array[] = { 5, 2, 2, 1, 0 };
int* p = stx::find_backward(array, array+5, 2, greater<int>());
cout << (p-array) << endl; // p = &array[1]

some

template<class InputIterator, 
           class T>
  bool
  some(InputIterator first, 
       InputIterator last, 
       const T&      val) 
  {
    while ( first != last ) {
      if ( *first == val ) {
        return true;
      }
      ++first;
    }
    return false;
  }

first <= i < last に対し、*i == value となる i が少なくともひとつあれば true を返します。

// sample
int array[] = { 5, 2, 2, 1, 0 };
bool t = stx::some(array, array+5, 1); // t = true;

some_if

template<class InputIterator, 
           class UnaryPredicate>
  bool
  some_if(InputIterator  first, 
          InputIterator  last, 
          UnaryPredicate pred) 
  {
    while ( first != last ) {
      if ( pred(*first) ) {
        return true;
      }
      ++first;
    }
    return false;
  }

first <= i < last に対し、pred(*i) != false となる i が少なくともひとつあれば true を返します。

// sample
bool gt1(int x) {
 return x > 1;
}

int array[] = { 0, 1, 0, 1, 0 };
bool t = stx:some_if(array, array+5, gt1); // t = false;

every

template<class InputIterator, 
           class T>
  bool
  every(InputIterator first, 
        InputIterator last, 
        const T&      val) 
  {
    while ( first != last ) {
      if ( !(*first == val) ) {
        return false;
      }
      ++first;
    }
    return true;
  }

first <= i < last であるすべての i に対し、*i == value であれば true を返します。

// sample
int array[] = { 2, 3, 4, 5, 6 };
bool t = stx::every(array, array+5, 3); // t = false;

every_if

template<class InputIterator, 
           class UnaryPredicate>
  bool
  every_if(InputIterator  first, 
           InputIterator  last,
           UnaryPredicate pred)
  {
    while ( first != last ) {
      if ( !pred(*first) ) {
        return false;
      }      
      ++first;
    }
    return true;
  }

first <= i < last であるすべての i に対し、pred(*i) != false であれば true を返します。

// sample
bool gt1(int x) {
 return x > 1;
}

int array[] = { 2, 3, 4, 5, 6 };
bool t = stx::every(array, array+5, 3); // t = true;

select_copy

template<class InputIterator, 
           class OutputIterator, 
           class T>
  OutputIterator
  select_copy(InputIterator  first, 
              InputIterator  last,
              OutputIterator result, 
              const T&       value) 
  {
    while ( first != last ) {
      if ( *first == value ) {
        *result = *first;
        ++result;
      }
      ++first;
    }
    return result;
  }

first <= i < last に対し、*i == value となる *i を [result,RET)にコピーします。RET は select_copy の戻り値です。

// sample
int array[] = { 5, 1, 2, 1, 0 };
vector<int> v;
stx::select_copy(array, array+5,back_inserter(V), 1); // v = { 1, 1 }

select_copy_if

template<class InputIterator, 
           class OutputIterator, 
           class UnaryPredicate>
  OutputIterator
  select_copy_if(InputIterator first, 
                 InputIterator last,
                 OutputIterator result, 
                 UnaryPredicate pred) 
  {
    while ( first != last ) {
      if ( pred(*first) ) {
        *result = *first;
        ++result;
      }
      ++first;
    }
    return result;
  }

first <= i < last に対し、pred(*i) != false となる *i を [result,RET)にコピーします。RET は select_copy の戻り値です。

// sample
bool gt1(int x) {
 return x > 1;
}

int array[] = { 5, 1, 2, 1, 0 };
vector<int> v;
stx::select_copy_if(array, array+5,back_inserter(V), gt1); // v = { 5, 2 }

transform_if

template<class InputIterator, 
           class OutputIterator,
           class UnaryFunction, 
           class UnaryPredicate>
  OutputIterator
  transform_if(InputIterator  first, 
               InputIterator  last,
               OutputIterator result, 
               UnaryFunction  fn,
               UnaryPredicate pred) 
  {
    while ( first != last ) {
      if ( pred(*first) ) {
         *result = fn(*first);
         ++result;
      }
      ++first;
    }
    return result;
  }

first <= i < last , pred(*i) != false となる i に対し、fn(*i)を [result,RET)にコピーします。RET は select_copy の戻り値です。

// sample
bool positive(int x) {
  return x > 0;
}

int twice(int x) {
  return x*2;
}

int array[] = { -2,  1,  0,  3,  2 }; 
vector<int> v;
stx::transform_if(array, array+5,back_inserter(V), twice, positive); // v = { 1*2,  3*2, 2*2 }
template<class InputIterator1, 
           class InputIterator2,
           class OutputIterator, 
           class BinaryFunction,
           class BinaryPredicate>
  OutputIterator
  transform_if(InputIterator1  first1,
               InputIterator1  last1,
               InputIterator2  first2,
               OutputIterator  result,
               BinaryFunction  fn,
               BinaryPredicate pred) 
  {
    while ( first1 != last1 ) {
      if ( pred(*first1,*first2) ) {
         *result = fn(*first1,*first2);
         ++result;
      }
      ++first1;
      ++first2;
    }
    return result;
  }

0 <= i < (last1 - first1), pred(*(first1+i),*(first2+i)) != false となる i に対し、fn(*(first1+i),*(first2+i))を [result,RET)にコピーします。RET は select_copy の戻り値です。

// sample
bool positive(int x, int y) {
  return x * y > 0;
}

int array1[] = { -2,  1,  0,  3, -2 }; 
int array2[] = { -2, -1,  0,  4,  2 }; 
vector&lt;int&gt; v;
stx::transform_if(array1, array1+5,
                    array2, back_inserter(V), 
                    multiplies<int>(), positive); // v = { 2*-2,  3*4 }

inject_1st

template<class InputIterator, 
           class BinaryFunction, 
           class T>
  T
  inject_1st(InputIterator  first, 
             InputIterator  last,
             BinaryFunction fn, 
             const T&       init) 
  {
    T result(init);
    while ( first != last ) {
      result = fn(result,*first);
      ++first;
    }
    return result;
  }

first <= i < last に対し、x = fn(x,*i); を順に適用し、最終的に選られたxを返します。x の型は T, 初期値は init です。

// sample
int array[] = { 1, 2, 3, 4, 5 };
int n = stx::inject_1st(array, array+5, plus<int>(), 0); // n = 15

inject_2nd

template<class InputIterator, 
           class BinaryFunction, 
           class T>
  T
  inject_2nd(InputIterator  first, 
             InputIterator  last,
             BinaryFunction fn, 
             const T&       init) 
  {
    T result(init);
    while ( first != last ) {
      result = fn(*first,result);
      ++first;
    }
    return result;
  }

first <= i < last に対し、x = fn(*i,x); を順に適用し、最終的に選られたxを返します。x の型は T, 初期値は init です。

// sample
int array[] = { 1, 2, 3, 4, 5 };
int n = stx::inject_2nd(array, array+5, plus<int>(), 0); // n = 15

partition_copy

template<class InputIterator, 
           class OutputIterator1,
           class OutputIterator2, 
           class UnaryPredicate>
  std::pair<OutputIterator1,OutputIterator2>
  partition_copy(InputIterator first, 
                 InputIterator last,
                 OutputIterator1 result1, 
                 OutputIterator2 result2,
                 UnaryPredicate pred) 
  {
    while ( first != last ) {
      if ( pred(*first) ) {
        *result1 = *first;
        ++result1;
      } else {
        *result2 = *first;
        ++result2;
      }
      ++first;
    }
    return std::pair<OutputIterator1,OutputIterator2>(result1,result2);
  }

first < i <= last に対し、pred(*i) != false ならば [result1,RET.first)に、pred(*i) == false ならば [result2,RET.second)に *iをコピーします。RET は partition_copy() の戻り値です。

// sample
bool positive(int x) {
  return x > 0;
}

int array[] = { 1, -2, 3, -4, 5 };
vector<int> v;
list<int> l;
stx::partition_copy(array, array+5, 
                      back_inserter(v), back_insserter(l),
                      positive); // v = { 1, 3, 5 }, l = { -2, -4 }

is_sorted

template<class InputIterator>
  bool
  is_sorted(InputIterator first, 
            InputIterator last) 
  {
    if ( first == last ) {
      return true;
    }
    InputIterator next = first;
    ++next;
    while ( next != last ) {
      if ( *next < *first ) {
        return false;
      }
      ++first;
      ++next;
    }
    return true;
  }

first <= i , i+1 <= last なるすべての i,i+1 に対し、*i < *(i+1) であれば true を返します。

// sample
int array[] = { 0, 1, 1, 2, 3 };
bool t = stx::is_sorted(array, array+5); // t = true;
template<class InputIterator, 
           class BinaryFunction>
  bool
  is_sorted(InputIterator first, 
            InputIterator last,
            BinaryFunction comp) 
  {
    if ( first == last ) {
      return true;
    }
    InputIterator next = first;
    ++next;    
    while ( next != last ) {
      if ( comp(*next,*first) ) {
        return false;
      }
      ++first;
      ++next;
    }
    return true;
  }

first <= i , i+1 <= last なるすべての i,i+1 に対し、comp(*(i+1),*i) == false であれば true を返します。

// sample
int array[] = { 3, 2, 2, 1, 0 };
bool t = stx::is_sorted(array, array+5, greater<int>()); // t = true;

lexicographical_compare_3way

template <class InputIterator1, 
            class InputIterator2>
  int
  lexicographical_compare_3way(InputIterator1 first1, 
                               InputIterator1 last1,
                               InputIterator2 first2, 
                               InputIterator2 last2) 
  {
    while (first1 != last1 && first2 != last2) {
      if (*first1 < *first2) {
        return -1;
      }
      if (*first2 < *first1) {
        return 1;
      }
      ++first1;
      ++first2;
    }
    if (first2 == last2) {
      return !(first1 == last1);
    } else {
      return -1;
    }
  }

2つのシーケンス[first1,last1), [first2,last2)を辞書順に比較し、[first1,last1) < [first2,last2) ならば -1、[first1,last1) = [first2,last2) ならば 0、[first1,last1) > [first2,last2) ならば 1 を返します。

// sample
string s1 = "apple";
const char* s2 = "apple";
int t = stx::lexicographical_compare_3way(s1.begin(), s1.end(), s2, s2+strlen(s2)); // t = 0
template <class InputIterator1, 
            class InputIterator2,
            class BinaryPredicate>
  int
  lexicographical_compare_3way(InputIterator1 first1, 
                               InputIterator1 last1,
                               InputIterator2 first2, 
                               InputIterator2 last2,
                               BinaryPredicate pred) 
  {
    while (first1 != last1 && first2 != last2) {
      if ( pred(*first1,*first2) ) {
        return -1;
      }
      if ( pred(*first2,*first1) ) {
        return 1;
      }
      ++first1;
      ++first2;
    }
    if (first2 == last2) {
      return !(first1 == last1);
    } else {
      return -1;
    }
  }

2つのシーケンス[first1,last1), [first2,last2)をpredに従って辞書順に比較し、[first1,last1) < [first2,last2) ならば -1、[first1,last1) = [first2,last2) ならば 0、[first1,last1) > [first2,last2) ならば 1 を返します。

// sample
bool ignorecase_less(char x, char y) {
  return toupper(x) < toupper(y);
}

string s1 = "apple";
const char* s2 = "APPLA";
int t = stx::lexicographical_compare_3way(s1.begin(), s1.end(), s2, s2+strlen(s2), 
                                              ignorecase_less); // t = -1