アレイのuniq、どう書く?(Mathematica)


どう書く?orgはなかなか面白いサイトなんだけど、ひとこと言わずにはいられなくなっていかん。

こんなのがあった。「アレイのuniq」

アレイ(複数の値が配列状になっているもの)xsが与えられたときに、同じ値が2回以上出現しないように、2回目以降の出現を取り除いたアレイを返すコードを書いてください。

まず思いつくのは、空のリスト(result)を作っておいて、入力(x)をScanしながら、resultの要素でない(Not@MemberQ)ものを加える(AppendTo)という方法。こんな感じ。(以下のコードはUMMでも動く。)

unsortedUnion[x_] := Module[{result = {}},
  Scan[If[Not@MemberQ[result, #], AppendTo[result, #]] &, x];
  result]

unsortedUnion@{3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9}

{3, 1, 4, 5, 9, 2, 6, 8, 7}

でも、既出かどうかはハッシュみたいな感じで調べた方が速いだろうから(メモリは喰うけど)、少し改良。

unsortedUnion[x_] := Module[{result = {}, mem},
  Scan[If[mem@# =!= True, mem@# = True; AppendTo[result, #]] &, x];
  result]

もうちょっときれいに書きたい。

Ver. 5で実装されたReapとSowを使う方法が、マニュアルに載っている(上の方法と比べて、パフォーマンスは圧倒的に高い。先の2つの実装はよくないってことは、マニュアルに書いてある)。

unsortedUnion[x_] := Reap[Sow[1, x], _, #1 &][[2]]

でも、「1」より「True」とか「Null」のほうがメモリ使用量は小さいから、こうしたほうがたぶん速い。

unsortedUnion[x_] := Reap[Sow[True, x], _, #1 &][[2]]

追記:実際に調べてみると、この方法が速くない場合もある(重複が多いとき?)。いずれにしても、皮肉なことに、Unionのほうがはるかに速そう。

追記:アレイのuniq、どう書く?(Mathematica 7)

Related posts:

  1. 油売り算(Mathematica)
  2. Puzzles for Hackers
  3. プレゼント交換の手伝い
  4. コラッツ予想(Mathematica, Lisp編)

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>