宜しくお願いします、下記の条件を満たしたプログラムを作りたいのですが
上手くいきません、ご教示ねがいます。
※ 条件
・配列x , 配列y 共に昇順に並んでいる。
・配列x , 配列y の要素数は等しくない。
・x[i] とy[i] が等しければz[i] に代入。
・配列y の要素は、配列x 以外の要素を持たない。
・配列y の要素が、配列x に含まれていなければ、その位置に0 を代入。( z[i]=0 )
・他のコンテナでも同じ振る舞いになること。
※ 現在の動作
IN
int x[6] = { 1, 2, 3, 4, 5, 6 };
int y[4] = { 1, 3, 4, 6 };
OUT
int z[6] = {1, 0, 0, 0, 0, 0 };
※ 期待する動作
OUT
int z[6] = {1, 0, 3, 4, 0, 6 };
#include <iostream>
#include <algorithm>
template <class T, class N>class IsEqual {
public:
T operator()(T t, N n){
return t == n ? t : 0;
}
};
int main() {
int x[6] = { 1, 2, 3, 4, 5, 6 };
int y[4] = { 1, 3, 4, 6 };
int z[6];
std::transform( x, x+6, y, z, IsEqual<int, int>());
for ( int i = 0; i < 6; ++i ) {
std::cout << z[ << x[i] << ] = << z[i] << std::endl;
}
return 0;
}
>・x[i] とy[i] が等しければz[i] に代入。
で
>int z[6] = {1, 0, 3, 4, 0, 6 };
は違う気がするけど。
x[i] と y[j] が等しければ z[i] に x[i] を代入、等しくなければ 0 を代入ってこと?
std::transform の5つの引数のやつは、3番目に渡すものの配列サイズが渡せないとお
もうので、関数オブジェクトのメンバとして持たせるのはどうでしょうか?
たとえば適当に
#include <iostream>
#include <algorithm>
#include <vector>
template <class T, class N>class IsEqual {
T* p_;
size_t s_;
// std::vector<T>* pv_;
public:
IsEqual(T* p, size_t s) : p_(p), s_(s) {}
T operator()(T t)
{
for (size_t i = 0; i < s_; ++i)
{
if (p_[i] == t) {
return t;
}
}
return 0;
}
// IsEqual(std::vector<T>* pv) : pv_(pv) {}
// T operator()(T t) {
// return (std::find(pv_->begin(), pv_->end(), t) != pv_->end()) ? t : 0;
// }
};
int main() {
int x[6] = { 1, 2, 3, 4, 5, 6 };
int y[4] = { 1, 3, 4, 6 };
// std::vector<int> y;
// y.push_back(1);
// y.push_back(3);
// y.push_back(4);
// y.push_back(6);
int z[6];
std::transform( x, x+6, z, IsEqual<int, int>(y, 4));
// std::transform( x, x+6, z, IsEqual<int, int>(&y));
for ( int i = 0; i < 6; ++i ) {
std::cout << z[ << x[i] << ] = << z[i] << std::endl;
}
return 0;
}
とか。
↑
は IsEqual の class N 全く使ってなかった。
IsEqual::operator()の
> return 0;
はTが数値型のときしかだめですね。
return T();
でいけたかしら。
Blue さん、ありがとうございます、期待していた動作です。
ところで、コンテナがvector である場合、template の部分特殊化。
または、オーバーロードによりvector コンテナのときに限った、動作を定義させること
はできないものでしょうか?
Blue さんの質問に答えていませんでした失礼しました
>x[i] と y[j] が等しければ z[i] に x[i] を代入、等しくなければ 0 を代入ってこと?
そういうことです。表現が変でしたすみません。それから
部分特殊化を調べたり、勉強しながら考えているのですが、上手くいきません?
#include <iostream>
#include <algorithm>
#include <vector>
template <class T>class IsEqual {
T* p_;
size_t s_;
public:
IsEqual(T* p, size_t s) : p_(p), s_(s) {}
T operator()(T t)
{
for (size_t i = 0; i < s_; ++i)
{
if (p_[i] == t) {
return t;
}
}
return T();
}
};
template <class T>class IsEqual<T *> {
std::vector<T>* pv_;
public:
IsEqual(std::vector<T>* pv) : pv_(pv) {}
T operator()(T t) {
return (std::find(pv_->begin(), pv_->end(), t) != pv_->end()) ? t : 0;
}
};
int main() {
typedef std::vector<int> VEC;
int x[6] = { 1, 2, 3, 4, 5, 6 };
int z[6];
//int y[4] = { 1, 3, 4, 6 };
//std::transform(x, x+6, z, IsEqual<int>(y, 4));
//for ( int i = 0; i < 6; ++i ) {
// std::cout << z[ << x[i] << ] = << z[i] << std::endl;
//}
VEC y;
y.push_back(1);
y.push_back(3);
y.push_back(4);
y.push_back(6);
VEC::iterator iter = y.begin();
int len = sizeof(x)/sizeof(int);
std::transform( x, x+len, z, IsEqual<int>(iter)); // ここの書き方が分かりません?
for ( int i = 0; i < 6; ++i ) {
std::cout << z[ << x[i] << ] = << z[i] << std::endl;
}
return 0;
}
なんとか、std:vector<int> 型をtemplate 部分特殊化することが出来ました。
掲示はしませんが、int 型へ特殊化することも成功しました、しかし思うに、
更に汎用的に扱いたければ、iterator 、ネィティブな配列でのアクセスできれば、より
多くの関数を効率よく生成することが出来そうですね。
もう少しEffective な方法を思案してみます。
#include <iostream>
#include <algorithm>
#include <vector>
template <class T>class IsEqual {
T* p_;
size_t s_;
public:
IsEqual(T* p, size_t s) : p_(p), s_(s) {}
T operator()(T t)
{
for (size_t i = 0; i < s_; ++i)
{
if (p_[i] == t) {
return t;
}
}
return T();
}
};
template <>class IsEqual<int> {
std::vector<int>* pv_;
public:
IsEqual(std::vector<int>* pv) : pv_(pv) {}
int operator()(int t) {
return (std::find(pv_->begin(), pv_->end(), t) != pv_->end()) ? t : 0;
}
};
int main() {
int x[6] = { 1, 2, 3, 4, 5, 6 };
int z[6];
//int y[4] = { 1, 3, 4, 6 };
//std::transform(x, x+6, z, IsEqual<int>(y, 4));
//for ( int i = 0; i < 6; ++i ) {
// std::cout << z[ << x[i] << ] = << z[i] << std::endl;
//}
std::vector<int> y;
y.push_back(1);
y.push_back(3);
y.push_back(4);
y.push_back(6);
int len = sizeof(x)/sizeof(int);
std::transform( x, x+len, z, IsEqual<int>(&y));
for ( int i = 0; i < 6; ++i ) {
std::cout << z[ << x[i] << ] = << z[i] << std::endl;
}
return 0;
}
こんな感じにしたらどうでしょうか?
template<class _InIt, class _Ty>
class IsEqual {
_InIt First;
_InIt Last;
public:
IsEqual(_InIt _First, _InIt _Last) : First(_First), Last(_Last) {}
_Ty operator()(_Ty _Val) {
return (std::find(First, Last, _Val) != Last) ? _Val : _Ty();
}
};
// vector
std::transform(x, x + 6, z, IsEqual<std::vector<int>::iterator, int>(y.begin(),
y.end()));
// 配列
std::transform(x, x + 6, z, IsEqual<int*, int>(y, y + 4));
Blue さん、お世話になります。
iterator をpointer に置き換えるテクニックですね、ご教授ありがとうございます。
さて、「C++テンプレートテクニック」という本を最近購読し、この本を勉強しているの
ですが
Blue さんは、ご存知かと思いますが、この本の中に「SFINAE」Substitution Failure Is
Not An Error
という技術が紹介されています、直訳すると「置き換え失敗はエラーじゃない」と
大変格好悪い訳になりますが、この技術に魅せられてしまいました
運よくtransform の実装が掲載されていたので、そこでこのIsEqual を組み込もうとしたら、
引数の数を勘違いしており子2時間、悶々としていましたが、今さっき間違いに気付き、
修正し上手く組み込めました。
大変ありがとうございました、すっきりしました。
// transform
template <class Range, class InputIterator, class OutputIterator, class
BinaryOperation>
OutputIterator transform
(
const Range& r,
InputIterator first,
OutputIterator result,
BinaryOperation op
)
{
return std::transform(begin(r), end(r), first, result, op);
}
※ begin(r), end(r)はネイティブなC言語配列でも、イテレータと同じように実装できる
(凄い!)
# 今日はゴミの日^^;
> 「C++テンプレートテクニック」
なんか地味に売れてますねぇ。ありがたやありがたや。
ゴミだけじゃァレなので lambda 使ってみたよ♪
// Visual Studio 2010β で検証済
#include <iostream>
#include <algorithm>
int main() {
int x[6] = { 1, 2, 3, 4, 5, 6 };
int y[4] = { 1, 3, 4, 6 };
int z[6];
std::transform(x, x+6, z,
[&](int v) { return std::find(y,y+4,v) == y+4 ? 0 : v; }); // あほほど楽チン
std::for_each(z, z+6, [](int v) { std::cout << v << ' ';});
}