イテレータの走査範囲を上手くコントロールするには?

[戻る]
秋雨 2009/11/02(月) 15:33:13
よろしくお願いいたします。コンパイラはVS2008Expressです。
データの順位を求めるプログラムですが条件があります。
データは昇順に並んでおり、且つそのデータに同順位が含まれる場合の条件として
同順位がある場合は、順位間の平均を順位として用います。
(例)3位が3つあった場合は、(3位+4位+5位)÷3 = 4位 を順位
このような計算を行うプログラムを、このように実装しましたが、このプログラムは思い
通りの動作を行いません。
範囲を走査するイテレータの動作範囲が一定でなく不確定な範囲を走査してしまうかから
だと思われます。
double array[] = {1.0, 2.0, 2.0, 2.0, 5.0, 6.0, 7.0, 7.0, 9.0, 10.0, 10.0, 10.0};
また。このように後半に同値のデータが連続する場合にも、範囲を逸脱してしまい、期待
通りの動作とはなりません。
このようなプログラムを実装するにはどのような、考えや設計を行えばよいのでしょうか。

#include <iostream> //cout
#include <vector>

// 範囲の平均値を取得
template <class T>
T Average(T t1, T t2)
{
    T result = 0;
    int limit;
    limit = (int)t2;
    for(int i = 0; i < limit; ++i) {
        result += t1;
        ++t1;
    }
    return result/t2;
}

template <class Iterator, class OutputIterator>
void PartAverage(Iterator first, const Iterator last, OutputIterator out)
{
    typedef typename std::iterator_traits<Iterator>::value_type value_type;
    value_type tmp;        // 反復値の総和
    value_type ave;        // 反復値の平均値
    Iterator p, p2, p3;    // 範囲を
    bool IsNonLimit = true;
    size_t Idx = 0;        // 反復した回数
    p = first;
    Iterator const limit = last-1;
    while(p != limit)
    {
        tmp = 0.0;
        Idx = 0;
        IsNonLimit = true;
        for(p3 = p; p3 != limit; ++p3) {
            p2 = p3;
            ++p2;
            // 非連続データの出力
            if( *p3 != *p2 && IsNonLimit == true )
            {
                *out = *p3;
                ++out;
                ++p;
                break;
            } else if(!IsNonLimit) {
                // 連続データの出力
                ++Idx;
                ave = Average<value_type>(*p3, Idx);
                for(size_t i = 0; i < Idx; ++i) {
                    *out = ave;
                    ++out;
                }
                ++p;
                break;
            } else {
                // 連続データのストック
                tmp += *p3;
                ++Idx;
                ++p;
                ++p2;
                if(*p!=*p2) {
                    IsNonLimit = false;
                }
                --p2;
            }
        }
    }
}

using namespace std;
int main()
{
    double array[] = {1.0, 2.0, 2.0, 2.0, 5.0, 6.0, 7.0, 7.0, 9.0, 10.0};
    vector<double>lhs(array, array+10);
    vector<double>vec(10);
    PartAverage<vector<double>::iterator , vector<double>::iterator>(lhs.begin(),
lhs.end(), vec.begin());
    copy(vec.begin(), vec.end(), std::ostream_iterator<double>(cout, " "));
    return 0;
}

επιστημη [E-Mail] [HomePage] 2009/11/02(月) 16:21:44
>(例)3位が3つあった場合は、(3位+4位+5位)÷3 = 4位 を順位

ちょっと質問。 三位がふたつあった場合は (3位+4位)÷2 = 3.5位 ?

秋雨 2009/11/02(月) 16:27:16
επιστημη さんお世話になります。
>>三位がふたつあった場合は (3位+4位)÷2 = 3.5位 ?
はい、その通りです。

επιστημη [E-Mail] [HomePage] 2009/11/02(月) 17:13:51
↓こんなんでいいんかなー...(自信ナシ)

#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <functional>

using namespace std;
int main()
{
    double array[] = {1.0, 2.0, 2.0, 2.0, 5.0, 6.0, 7.0, 7.0, 9.0, 10.0};

    double* first = array;
    double* last  = array+10;
    
    while ( first != last ) {
      double* mid = adjacent_find(first, last, not_equal_to<double>());
      if ( mid != last ) ++mid;
      double rank = distance(array,first)+1 + (distance(first,mid)-1)/2.0;
      while ( first != mid ) {
        cout << rank << ' ';
        ++first;
      }
    }
    return 0;
}

季節はずれのゴムボート 2009/11/02(月) 19:33:05
[[解決]]
επιστημη さんお世話になります。
ありがとうございます。std::vector<T>の検証と
double array[] = {1.0, 2.0, 2.0, 2.0, 5.0, 6.0, 7.0, 7.0, 9.0, 10.0, 10.0, 10.0};
最後の値が連続する場合も期待通りの結果が得られましたことを報告します。

#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <functional>

using namespace std;
int main()
{
    //use T[]
    double array[] = {1.0, 2.0, 2.0, 2.0, 5.0, 6.0, 7.0, 7.0, 9.0, 10.0};

    double* first = array;
    double* last  = array+10;

    while ( first != last ) {
        double* mid = adjacent_find(first, last, not_equal_to<double>());
        if ( mid != last ) ++mid;
        double rank = distance(array,first)+1 + (distance(first,mid)-1)/2.0;
        while ( first != mid ) {
            cout << rank << ' ';
            ++first;
        }
    }
    cout << "\n";

    //use std::vector<T>
    vector<double>lhs(array, array+10);

    vector<double>::iterator first_ = lhs.begin();
    vector<double>::iterator last_ = lhs.end();

    typedef vector<double>::iterator ITERATOR;
    
    while ( first_ != last_ ) {
        ITERATOR mid_ = adjacent_find(first_, last_, not_equal_to<double>());
        if ( mid_ != last_ ) ++mid_;
        double rank_ = distance(lhs.begin(),first_)+1 + (distance(first_,mid_)-1)/2.0;
        while ( first_ != mid_ ) {
            cout << rank_ << ' ';
            ++first_;
        }
    }
    return 0;
}

επιστημη [E-Mail] [HomePage] 2009/11/02(月) 21:41:04
アナタ誰?

PATIO 2009/11/04(水) 09:55:00
ハンドルネームは、なるべく統一してほしいですね。
一々本人なのか確認するのは手間ですし。

故意ではないかもしれませんけれど、
なるべく統一する方向でお願いします。

επιστημη [E-Mail] [HomePage] 2009/11/04(水) 12:29:12
「複数ハンドルは別に構わんが辻褄は合わせておくれ」が僕の意見。
つか、「ちゃんと使えんものを使うな」かな。

古いスレッドには追加発言できません。