パスワードを忘れた? アカウント作成
13848268 journal
日記

quaternionの日記: C++で畳み込み 23

日記 by quaternion

PythonとC++で畳み込み(fold)をそれぞれ書いてみた.

C++だとどうしても長くなってしまう.

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
  • by qwerty (20776) on 2019年02月27日 17時45分 (#3572237) 日記

    perl -e '@c=(1,2,3,4,5); $c = eval join("+",@c); print $c, "\n"'

    # eval 利用が邪道かどうかは意見が分かれそう

    --
    [Q][W][E][R][T][Y]
    • by route127 (38618) on 2019年03月01日 23時25分 (#3573555) 日記

      文字列と数値を行き来してevalするのがperl 4っぽい気がする(貶してないです)。
      自分が書くなら、grepで

      perl -e "grep{$total+=$_}1..5;print $total;"

      ですかね。

      親コメント
    • by Anonymous Coward

      joinはfoldの特殊ケースだ
      そんなものを書いてると一般論を理解せず特殊ケースを弄んで喜ぶゴミプログラマーになるし、邪道なのをevalのせいにしているお前はそうなりかかっている

      • by Anonymous Coward

        dfのクエリーをユーザが入力した不等式で書き換えるとかやってうんざりしている私はまだ大丈夫なのですね

      • by Anonymous Coward

        これを特殊ケース言うなら元ブログの畳み込みの説明が間違ってるし
        convolution じゃなくて folding で + なら join でも構わんでしょ

        @c = (1,2,3,4,5);
        $c = shift(@c);
        map { $c = $c + $_ ; } @c;
        print $c, "\n";

        • by Anonymous Coward

          いいわけあるか
          何の集合の上の二項演算か、単位元は何なのか把握していないから日記主のように

          > 見落としていました!感謝です.

          理解していないものを見落としたと間違えてしまう

  • 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(集計)って呼ぶのがいかにも手続き型言語ぽいね。

  • by minet (45149) on 2019年02月28日 9時29分 (#3572547) 日記

    リンク先には「演算子 * の部分には任意の二項演算子を書ける.」とありますが、
    記載の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; });
    です。

  • by Anonymous Coward on 2019年02月27日 17時06分 (#3572198)

    fn main() {
            let a = vec![1, 2, 3, 4, 5];

            let sum = a.iter().fold(1, |x, y| x * y);

            println!("{}", sum);
    }

  • by Anonymous Coward on 2019年02月27日 21時42分 (#3572395)

    #include <iostream>
    #include <numeric>

    int main() {
        int a[] = { 1, 2, 3, 4, 5 };
        std::cout << std::accumulate(a, a+sizeof(a)/sizeof(int), 1, [](int x, int y) { return x*y; }) << std::endl;
    }

    • リンク先のPython版が、結果を中間変数に入れずに直接出力しているので、
      それに合わせるならC++版もstd::coutに直接流し込め、ってことですね。

      しかしvectorを配列にするのは良い変更とは言い難い。
      末尾位置をポインタ演算で得るために、かえって記述が増えてますよ。

      親コメント
      • by Anonymous Coward

        Python版で組み込み array を使っているのなら、C++版でもそうしろ、ってこと。配列末端の計算で長くなるのは同意だけど。

        • C++11なコードで、C++なstd::accumulateまでを使ってるんですから、C++11での標準的なコンテナは使っても問題ないのでは。
          で、固定長の配列なら、std::array を使って、

            std::array<int,5> a = { 1, 2, 3, 4, 5 };
            std::cout << std::accumulate(a.cbegin(), a.cend(), 1, [](int x, int y) { return x*y; }) << std::endl;

          でいいんじゃないかな。生の配列に対してオーバーヘッドなく、しかもイテレータも使えます。

          要素数まで指定しないといけないのが玉に瑕ですが、使ったことはないですがC++17なら、

          auto a = std::make_array(1, 2, 3, 4, 5);

          で、要素数も省略できるようになったはず

          親コメント
          • by Anonymous Coward

            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を前提にするような言語だからコア言語縛りにもあまり意味があるとは思えないし

  • by Anonymous Coward on 2019年02月28日 10時40分 (#3572573)

    まず畳み込みという日本語からして、コンボリューションと被っている上に、畳み込み積分は畳み込み関数でスマートに書けたりするのでややこしい。

    で、関数名で調べようと思ったら、言語ごとにfoldだったり、reduceだったり、injectだったり。
    Rubyの場合、書いた日によって、reduceとinjectが混在していたりする(多分ググった時のトップに何が来るかで変わってる)。

    # injectとreduceって矛盾してない?

    • "inject"はjoinやsumのように、結果オブジェクトに値をぶち込んでいくイメージ、
      "reduce"は集合の次元を減らす(2次元配列を与えるなら1次元配列を得る。1次元配列を与えるならスカラーを得る)イメージ
      なんじゃないかな…と思ってます
      #ぜんぜん違うかも

      親コメント
      • by Anonymous Coward

        reduceはlisp由来

        injectは由来元のSmalltalkでは

        (1 to: 10) inject: 0 into: [:result :each | result + each]

        と使い、inject: into:がセレクターになり、メソッドが選ばれる
        なんでこんなことをするのかというと自然言語に近づけるためで、ちゃんと論文にそう書いてある
        Smalltalkの名前の由来もその自然言語指向から来ている
        大昔に図書館で読んだたぶんIngallsの非常に古い論文だから、タイトルはわからなくてすまんな

        matzは馬鹿だからそれをぜんぜん理解しなかった
        馬鹿は有害なんだよ

        • by Anonymous Coward

          Smalltalkのオブジェクト指向は 存在論ontology [wikipedia.org]なんだ
          それまでは認識論 [wikipedia.org]一辺倒だった
          これもちゃんと論文に書いてあるからな
          Matzをはじめ無教養で論文も読まない馬鹿は、自分が馬鹿だと知らないから好き勝手なことを言う
          初心者を有用な情報から遠ざけ、有害きわまりない

          今は情報科学にも

          • by Anonymous Coward

            思いて学ばざれば則ち殆うしということですね。
            しかしいくら発言が有用であっても不快であれば評価は上がらないでしょう。
            あなたがマイナスモデされるのはそこなんじゃないかな。
            初心者を馬鹿を落とさず引き上げるには、有用かつ快な発言のできるエヴァンジェリストが求められるところ。

            初心者に「論文って面白いな!自分も読んでみよう!」と思わせるブログでも書いてみてはいかが。

            • by Anonymous Coward

              > しかしいくら発言が有用であっても不快であれば評価は上がらないでしょう。

              そこが問題なんだよ
              不快だからプチ権力をふるって気に入らない相手を沈める、民主主義にはそれが一番ダメなんだ

              • by Anonymous Coward

                かもしれないけど自分は周りが不快であるよりは快で満ちている方がいいなー
                ま、あなたの言った「ちゃんと論文に書いてある」にはある種の感銘を受けたから、まずはスラドを読むときから、記事に論文がリンクされていたらまずその論文を読もう、とは思った。

typodupeerror

日本発のオープンソースソフトウェアは42件 -- ある官僚

読み込み中...