PythonとC++で畳み込み(fold)をそれぞれ書いてみた. C++だとどうしても長くなってしまう.
13848268 journal quaternionの日記: C++で畳み込み 23 日記 by quaternion 2019年02月27日 10時21分 PythonとC++で畳み込み(fold)をそれぞれ書いてみた. C++だとどうしても長くなってしまう.
perl で書いてみる (スコア:1)
perl -e '@c=(1,2,3,4,5); $c = eval join("+",@c); print $c, "\n"'
# eval 利用が邪道かどうかは意見が分かれそう
[Q][W][E][R][T][Y]
Re:perl で書いてみる (スコア:1)
文字列と数値を行き来してevalするのがperl 4っぽい気がする(貶してないです)。
自分が書くなら、grepで
ですかね。
Re: (スコア:0)
joinはfoldの特殊ケースだ
そんなものを書いてると一般論を理解せず特殊ケースを弄んで喜ぶゴミプログラマーになるし、邪道なのをevalのせいにしているお前はそうなりかかっている
Re: (スコア:0)
dfのクエリーをユーザが入力した不等式で書き換えるとかやってうんざりしている私はまだ大丈夫なのですね
Re: (スコア:0)
これを特殊ケース言うなら元ブログの畳み込みの説明が間違ってるし
convolution じゃなくて folding で + なら join でも構わんでしょ
@c = (1,2,3,4,5);
$c = shift(@c);
map { $c = $c + $_ ; } @c;
print $c, "\n";
Re: (スコア:0)
いいわけあるか
何の集合の上の二項演算か、単位元は何なのか把握していないから日記主のように
> 見落としていました!感謝です.
理解していないものを見落としたと間違えてしまう
C#ていうか.NetだとAggregateかな (スコア:1)
using System.Linq;
public class Hoge
{
public static void Main()
{
var arr = new [] {1, 2, 3, 4, 5};
var result = arr.Aggregate((a, b) => a * b);
System.Console.WriteLine(result);
}
}
Aggregate(集計)って呼ぶのがいかにも手続き型言語ぽいね。
C++版の初期値に問題 (スコア:1)
リンク先には「演算子 * の部分には任意の二項演算子を書ける.」とありますが、
記載のC++版は * に任意の二項演算子を入れると必ずしも正しい結果にはなりません。
例えば + です。
というのは、std::accumulate() の第3引数は「集計の初期値」なので、
集合全体に適用して畳み込みを行うには、二項演算の単位元を指定する必要があります。
(例えば * なら 1、+ なら 0)
ワークアラウンドとしては、先頭の要素を初期値とし、2番めの要素から集計をかけます。
つまり
int sum = std::accumulate (std::next(a.begin()), a.end(), *a.begin(), [](int x, int y) { return x * y; });
です。
Re:C++版の初期値に問題 (スコア:2)
見落としていました!感謝です.
Quora記事、直っていません… (スコア:1)
第3引数に先頭要素の値を渡す場合、第1引数に渡すのは先頭位置のイテレーターではなくて先頭の次のイテレーターです。
× int sum = std::accumulate(a.cbegin(), a.cend(), *a.cbegin(), [](int x, int y) { return x*y; });
○ int sum = std::accumulate(std::next(a.cbegin()), a.cend(), *a.cbegin(), [](int x, int y) { return x*y; });
Rust で書いてみる (スコア:0)
fn main() {
let a = vec![1, 2, 3, 4, 5];
let sum = a.iter().fold(1, |x, y| x * y);
println!("{}", sum);
}
C++版は少なくとも後 3行短くできる (スコア:0)
Re:C++版は少なくとも後 3行短くできる (スコア:1)
リンク先のPython版が、結果を中間変数に入れずに直接出力しているので、
それに合わせるならC++版もstd::coutに直接流し込め、ってことですね。
しかしvectorを配列にするのは良い変更とは言い難い。
末尾位置をポインタ演算で得るために、かえって記述が増えてますよ。
Re: (スコア:0)
Python版で組み込み array を使っているのなら、C++版でもそうしろ、ってこと。配列末端の計算で長くなるのは同意だけど。
Re:C++版は少なくとも後 3行短くできる (スコア:1)
C++11なコードで、C++なstd::accumulateまでを使ってるんですから、C++11での標準的なコンテナは使っても問題ないのでは。
で、固定長の配列なら、std::array を使って、
でいいんじゃないかな。生の配列に対してオーバーヘッドなく、しかもイテレータも使えます。
要素数まで指定しないといけないのが玉に瑕ですが、使ったことはないですがC++17なら、
で、要素数も省略できるようになったはず
Re: (スコア:0)
std::arrayにしろstd::make_arrayにしろ#include <array>が必要(1行増える)でしょ。
そもそもC++11なら配列でもstd::begin(a)とstd::end(a)で普通に先頭と末尾が取れるけど、#include <iterator>が必要でやっぱり1行増える。
コードゴルフじゃあるまいし、1行増えるからといって要素数を手計算すべきではないと思いますけどね。range based forがstd::beginとstd::endを前提にするような言語だからコア言語縛りにもあまり意味があるとは思えないし
名前をなんとかしてほしい(オフトピ) (スコア:0)
まず畳み込みという日本語からして、コンボリューションと被っている上に、畳み込み積分は畳み込み関数でスマートに書けたりするのでややこしい。
で、関数名で調べようと思ったら、言語ごとにfoldだったり、reduceだったり、injectだったり。
Rubyの場合、書いた日によって、reduceとinjectが混在していたりする(多分ググった時のトップに何が来るかで変わってる)。
# injectとreduceって矛盾してない?
Re:名前をなんとかしてほしい(オフトピ) (スコア:1)
"inject"はjoinやsumのように、結果オブジェクトに値をぶち込んでいくイメージ、
"reduce"は集合の次元を減らす(2次元配列を与えるなら1次元配列を得る。1次元配列を与えるならスカラーを得る)イメージ
なんじゃないかな…と思ってます
#ぜんぜん違うかも
Re: (スコア:0)
reduceはlisp由来
injectは由来元のSmalltalkでは
(1 to: 10) inject: 0 into: [:result :each | result + each]
と使い、inject: into:がセレクターになり、メソッドが選ばれる
なんでこんなことをするのかというと自然言語に近づけるためで、ちゃんと論文にそう書いてある
Smalltalkの名前の由来もその自然言語指向から来ている
大昔に図書館で読んだたぶんIngallsの非常に古い論文だから、タイトルはわからなくてすまんな
matzは馬鹿だからそれをぜんぜん理解しなかった
馬鹿は有害なんだよ
Re: (スコア:0)
Smalltalkのオブジェクト指向は 存在論ontology [wikipedia.org]なんだ
それまでは認識論 [wikipedia.org]一辺倒だった
これもちゃんと論文に書いてあるからな
Matzをはじめ無教養で論文も読まない馬鹿は、自分が馬鹿だと知らないから好き勝手なことを言う
初心者を有用な情報から遠ざけ、有害きわまりない
今は情報科学にも
Re: (スコア:0)
思いて学ばざれば則ち殆うしということですね。
しかしいくら発言が有用であっても不快であれば評価は上がらないでしょう。
あなたがマイナスモデされるのはそこなんじゃないかな。
初心者を馬鹿を落とさず引き上げるには、有用かつ快な発言のできるエヴァンジェリストが求められるところ。
初心者に「論文って面白いな!自分も読んでみよう!」と思わせるブログでも書いてみてはいかが。
Re: (スコア:0)
> しかしいくら発言が有用であっても不快であれば評価は上がらないでしょう。
そこが問題なんだよ
不快だからプチ権力をふるって気に入らない相手を沈める、民主主義にはそれが一番ダメなんだ
Re: (スコア:0)
かもしれないけど自分は周りが不快であるよりは快で満ちている方がいいなー
ま、あなたの言った「ちゃんと論文に書いてある」にはある種の感銘を受けたから、まずはスラドを読むときから、記事に論文がリンクされていたらまずその論文を読もう、とは思った。