読者です 読者をやめる 読者になる 読者になる

倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

そこまで言って委員会 NP 2017年3月26日

そこまで言って委員会

緊急スペシャル ニッポンの医療は病んでいるのか!?

医療事件簿 最大の“謎”は?

第1話「続発する医療事件の謎

  • 医療事件簿カルテ1 群馬大学病院 手術死問題
  • 医療事件簿カルテ2 横浜連続点滴死事件
  • 医療事件簿カルテ3 京都府医大事件
パネラー 答え
長尾和宏 誰も本当のことを言わない!
田豊 なぜチェック体制が働かなかった?
武内和久 「見ざる言わざる聞かざる」
川渕孝一 「真の原因」がよくわからない
丸田佳奈 病院組織の管理の限界!?
守谷順 点検システムや情報の取り扱いはどうなっているのか?
梅村聡 医療現場に「監督」「コーチ」が不在
森山明宏 なぜ組織のガバナンスが機能しなかった?

群馬大学病院の事件、第一外科と第二外科が売り上げを開示して手術数を競わせていたが、第一外科は執刀医が多くいたのに対して、第二外科は事実上執刀医が1人で、無理なスケジュールで手術してたとか。 なんか、医療に最悪な形で競争原理入れてしまったような事案ですな。

医者にとっては、やくざ来ても一般人と変わらない医療を提供しようという矜持はあるけど、学長や病院長の命令には絶対服従。 まぁ、仕方ないですかね。

病院の経営は医者でない人間にさせるというのは試してみて欲しい気もするけど、実際のところどうなんでしょう。 よく、医療事故の裁判とかで裁判官や弁護士は医療に詳しくないので・・・みたいな話はあるけど、医療に詳しい弁護士というのも(数はともかく)いると思うので、経営に関してもそういう人がいれば、というか育てればいいんでは。 でも医者に経営教えた方が早い気もするが。

辛坊氏、手術が初めての医者に執刀されるのは云々と言ってたけど、たしか前にもこの番組で同じこと言ってたよな。 んで、(確か森田氏に)同じ答えをされてたと思うんだが。 せっかく医者に質問する機会を得たのに、質問した結果(質問したこと自体)を覚えてないのは勿体ない。 ところrで、初の執刀時には2~3人ベテランの医師がついてるとのことなので、むしろ普通に手術受けるより安全なんじゃないの?という気はするな。 福島産の米は全袋検査してるのでむしろ世界一安全な米だ、みたいな?

医療費削減 どうすれば良い?

第2話「膨らむ医療費

パネラー 答え
長尾和宏 多剤投与の解消
田豊 寿命が延びる限りどうすることもできない!
武内和久 「削減ありき」ではダメ
川渕孝一 セルフメディケーション税制の拡大
丸田佳奈 予防に重きをおいた啓蒙活動
守谷順 削減よりも他に優先すべきは・・・
梅村聡 健康管理にインセンティブをつけた医療保険
森山明宏 厚労省の「マッチポンプな政策」の是正

医療費2015年度40兆円超え。 国民1人あたりにすると、年間医療費は約32万7000円。 高齢者を年代別に見ると、75歳未満約22万円に対して、75歳以上の後期高齢者約94万8000円だとか。 こんなに差があるのね。 年齢より収入とかで分けた方がいいんじゃないかと思ったら、2018年8月から高額療養制度でいくらかそういう風になるみたいね。

調剤費約6800億円増。 それなりにニュースになったオプジーボ、肺癌の場合、体重60kgの人が1年間使うと約3500万円。 2月から半額になったそうだけど。 製薬会社のことを考えると、一概に批判だけをするのも気が引けるけど。

桂ざこば 経営者、ドクター、製薬会社、医療機器メーカー、一番儲かるのは?

薬をたくさん出しても医者は基本的に儲からないらしい(いくらかは儲かるらしい)。 薬局や製薬会社が儲かるというのもあるんだろうけど、患者側が薬を出して欲しがるという問題もあるみたいね。 まぁ、水素水があれだけヒットする社会なので仕方ないかとも思うがw
病気の9割は歩くだけで治る! ~歩行が人生を変える29の理由~ 簡単、無料で医者いらず

薬剤は公定価格が決まっているけど、医療機器は値段が決まっていなくて、ほとんど同じ性能の機器(少しだけマイナーチェンジした程度のもの)でも、公的病院と市立病院で値段が10倍くらい違うらしい。 公的病院では基本的に税金で機器を買うので、この差はもろに税金がつぎ込まれてるという・・・

あなたの身近にサイコパスはいますか?

第3話「サイコパスはそこにいる

パネラー いる or いない 答え
長尾和宏 いる 医者には多い 人を人とも思わない
田豊 いない 私が気づいてないだけかも・・・
武内和久 いない でもこれからの政治家には必要
川渕孝一 いる 留学生の中にも・・・
丸田佳奈 いない 私の周りにはいませんが・・・
守谷順 いない “定義”にもよりますが・・・
梅村聡 いない そう感じた経験がない
森山明宏 どちらともいえない 2, 3年周期で転々とする勤務医には・・・

サイコパス度が高い職業:企業経営者、弁護士、メディア関係者。
PSYCHO-PASS サイコパス Blu-ray BOX 6枚組

あなたは尊厳死を望みますか?

最終回「死ぬ権利

パネラー 望む or 望まない 答え
長尾和宏 望む 「在宅看取り」はすべて「尊厳死」「枯れて死ぬこと」
田豊 望む 「消極的安楽死」なら・・・
武内和久 望まない 「死」を本人に意思決定させるのはおかしい
川渕孝一 望む なし崩し的な「安楽死」が広がる前に「尊厳死」の制度化を
丸田佳奈 望む でも医師として制度化は望まない
守谷順 望む 本人の意思を尊重すべき! 安楽死さえ
梅村聡 望む 麻生大臣とのやりとりで・・・
森山明宏 望む 基準を設けて認めるべき
竹田恒泰 望む
中田宏 望む
金美麗 望む
長谷川幸洋 望む
桂ざこば 望む

日本尊厳死協会では「半年以上の植物状態で本人の意思(リビング・ウィル)があること」を尊厳死ガイドラインとしてるそうで。 ただ、ほとんどの場合リビング・ウィルがされてないようなので、

リビング・ウイル
自分の延命治療について事前に要望を明記しておく文書。

リビング・ウィルが法整備されていないのは先進国では日本だけで、一筆書いても日本では有効でないらしい。 障害・難病の団体から反対されて議論が止まっているとのこと。 まぁ、そちら側の主張は知らないのでいいのか悪いのか何とも言えないけど。 海外では法律を作ると返って尊厳死しにくくなる場合もあるそうで。

難病患者、徐々に病状が悪化して人工呼吸器をつけないといけなくなったとき、つけるかどうかを本人に判断させる。 一度つけると現在の日本の法律では外せない。

勝手なイメージだけど、日本の文化ってもっと「死」に関して寛容でもおかしくなさそうなんだけど、違うのかなぁ。 人に殺されるとかは別として、病気や天災で命を落とすのは仕方ないとか居直っても良さそうなもんだが。 ざこば師匠の奥さん方の親族の話(小咄?)の「せっかく心臓止まったのに云々」ってくだりを笑えるような寛容さはけっこういいと思うんだけど。 まぁ、自分がどうかと言われれば死にたくはないし、難病にかかってたら世を恨みそうな気もするが。

そこまで言って委員会NP ニッポンの危機 [DVD]

Scala の Seq に定義されているメソッドを試す (9) ~タプル関連~

Scala

Scala の Seq に定義されているメソッドを試すシリーズ(目次)。 今回は Seq のタプルやタプルの Seq を返すメソッドを見ていきます。 Map はタプルの Seq なので groupBy メソッドもここで扱います。

今回扱うメソッド

def splitAt(n: Int): (Seq[A], Seq[A])
def span(p: (A) ⇒ Boolean): (Seq[A], Seq[A])
def partition(p: (A) ⇒ Boolean): (Seq[A], Seq[A])

def groupBy[K](f: (A) ⇒ K): Map[K, Seq[A]]

def zip[B](that: GenIterable[B]): Seq[(A, B)]
def zipAll[B](that: collection.Iterable[B], thisElem: A, thatElem: B): Seq[(A, B)]
def zipWithIndex: Seq[(A, Int)]

def unzip[A1, A2](implicit asPair: (A) ⇒ (A1, A2)): (Seq[A1], Seq[A2])
def unzip3[A1, A2, A3](implicit asTriple: (A) ⇒ (A1, A2, A3)): (Seq[A1], Seq[A2], Seq[A3])

サンプルコード

splitAt メソッド
splitAt メソッドは、指定した位置で Seq を2つに分割します。 take と drop で得られる部分 Seq をタプルにしたものと同じものが返されます(個別に呼ぶよりパフォーマンスはいいんでしょうけど)。

  val strSeq = Seq("a", "b", "c", "d", "e")

  // split メソッド
  assert( strSeq.splitAt(3) == (Seq("a", "b", "c"), Seq("d", "e")) )

  // take と drop で返される Seq をタプルにしたものと同じ
  assert( strSeq.splitAt(3) == (strSeq.take(3), strSeq.drop(3)) )

span メソッド
span メソッドは、要素に対する述語関数(Boolean 値を返す関数、条件式)を引数にとり、先頭からその条件を満たしている要素を集めて結果のタプルの第1要素に、それ以降の要素を集めて結果のタプルの第2要素にします。 takeWhile と dropWhile で返される Seq をタプルにして返す、と言った方が分かりやすいですかね。

  val intSeq = Seq(0, 1, 2, 3, 0, 1, 2, 3)

  // span メソッド
  assert( intSeq.span(_ < 3) == (Seq(0, 1, 2), Seq(3, 0, 1, 2, 3)) )

  // takeWhile と dropWhile で返される Seq をタプルにしたものと同じ
  val f: Int => Boolean = _ < 3
  assert( intSeq.span(f) == (intSeq.takeWhile(f), intSeq.dropWhile(f)) )

条件を満たさない要素が現れると、それ以降に条件を満たす要素が現れてもすべて結果のタプルの第2要素に含まれます。

partition メソッド
partition メソッドは、span メソッドと同じように要素に対する述語関数を引数にとりますが、要素全てを走査して、条件に合う要素を返り値のタプルの第1要素に、条件に合わない要素を返り値のタプルの第2要素にします。 言い換えると、filter と filterNot が返す Seq をタプルにしたものと同じものを返します。

  val intSeq = Seq(0, 1, 2, 3, 0, 1, 2, 3)

  // partition メソッド
  assert( intSeq.partition(_ < 3) == (Seq(0, 1, 2, 0, 1, 2), Seq(3, 3)) )

  // filter と filterNot で返される Seq をタプルにしたものと同じ
  assert( intSeq.partition(f) == (intSeq.filter(f), intSeq.filterNot(f)))

groupBy メソッド
groupBy メソッドは、要素を別の型のオブジェクトに変換し、変換後のオブジェクトが同じになる要素を集めて Map にしたものを返します。 数学っぽく言うと同値類を作るようなものですね。 返される Map のキーは変換後のオブジェクト、値はそのキーに変換される元の Seq の要素を集めた Seq オブジェクトとなります。

  val intSeq = Seq(0, 1, 2, 3, 4)

  // groupBy メソッド
  assert( intSeq.groupBy(_ % 3) == // 3で割った余りでグループ分け
    Map(0 -> Seq(0, 3),  // 3で割った余りが0
        1 -> Seq(1, 4),
        2 -> Seq(2)) )

前述の partition メソッドは、述語関数によって元の Seq の要素を Boolean 値に変換していると思えば、groupBy メソッドみたいなものとも思えます。

  val intSeq = Seq(0, 1, 2, 3, 0, 1, 2, 3)
  val f: Int => Boolean = _ < 3

  // groupBy メソッドと partition メソッド
  val parts = intSeq.partition(f)
  assert( intSeq.groupBy(f) == 
    Map(true  -> parts._1,  // 真偽値をキーとした Map
        false -> parts._2) )

zip メソッド
zip メソッドは、2つの Seq を先頭から順々にタプルにして Seq として返します。 返される Seq の n 番目の要素は、もとの2つの Seq の n 番目の要素をタプルにしたものになります。

  val strSeq = Seq("a", "b", "c", "d", "e")
  val intSeq0 = Seq(0, 1, 2, 3, 4)

  // zip メソッド
  assert( (strSeq zip intSeq0) ==
    Seq(
      ("a", 0),
      ("b", 1),
      ("c", 2),
      ("d", 3),
      ("e", 4)) )

2つの Seq の長さが異なる場合は、短い方に合わせられます。

  val strSeq = Seq("a", "b", "c", "d", "e")
  val intSeq1 = Seq(0, 1, 2)

  // Seq の長さが違う場合
  assert( (strSeq zip intSeq1) ==
    Seq(
      ("a", 0),
      ("b", 1),
      ("c", 2)) )

zip メソッドがやっていることは tranpose メソッドに似てるので、実際に transpose で書いてみると以下のようになります。

  val strSeq = Seq("a", "b", "c", "d", "e")
  val intSeq0 = Seq(0, 1, 2, 3, 4)

  // transpose 使って書いてみた
  assert( (strSeq zip intSeq0) ==
    Seq(strSeq, intSeq0).transpose.map(seq => (seq(0), seq(1))) )

Seq をタプルに返る map メソッド呼び出しがありますが、やってることは transpose のような組み替えですね。

zipAll メソッド
zip メソッドは2つの Seq の長さが異なる場合には短い方に合わせるように長い方の要素を切り捨てましたが、zipAll メソッドは長い方に合わせ、足りない分は引数に指定したオブジェクトで補います。

  val strSeq = Seq("a", "b", "c", "d", "e")
  val intSeq = Seq(0, 1, 2)

  // zipAll メソッド
  val result = strSeq.zipAll(intSeq, "null", -1)
  assert( result ==
    Seq(
      ("a", 0),
      ("b", 1),
      ("c", 2),
      ("d", -1),  // intSeq の長さが足りないので-1で補う
      ("e", -1)) )

今の場合、strSeq の方が短ければタプルの第1要素が "null" によって補われます。

zipWithIndex メソッド
zipWithIndex メソッドは、Seq のインデックスとの zip 結果を返します。

seq.zip(seq.indices)

インデックスの Int 値は0から始まり、タプルの第2要素となります。

  val strSeq = Seq("a", "b", "c", "d", "e")

  // zipWithIndex メソッド
  assert( strSeq.zipWithIndex ==
    Seq(
      ("a", 0),
      ("b", 1),
      ("c", 2),
      ("d", 3),
      ("e", 4)) )

使い方は以下のようになります。

  strSeq.zipWithIndex.map(x => s"${x._2}番目は${x._1}").foreach(println)

実行すると以下のような結果が表示されます。

0番目はa
1番目はb
2番目はc
3番目はd
4番目はe

もしくは、case 文で部分関数を書いて以下のようにすることもできます。

  strSeq.zipWithIndex.map{
    case (s, i) => s"${i}番目は$s"
  }.foreach(println)

実行結果は上記と同じです。

unzip メソッド
unzip メソッドは、zip メソッドとは逆に、1つの Seq オブジェクトを2つの Seq のタプルに分割します。 unzip メソッドの引数には、元の Seq オブジェクトの要素をタプルに変換する関数を渡します。

  val intSeq = Seq(0, 1, 2, 3, 4)

  // unzip メソッド
  val result = intSeq.unzip(n => (n/3, n%3))  // 3で割った商と余りのタプル
  assert( result == 
    (Seq(0, 0, 0, 1, 1),
     Seq(0, 1, 2, 0, 1)) )

zip メソッドも transpose みたいなことをしてるので transpose で書いてみた。

  val intSeq = Seq(0, 1, 2, 3, 4)

  // zip メソッドを transpose で書いてみた
  val transposed = intSeq.map(n => Seq(n/3, n%3)).transpose
  assert( intSeq.unzip(n => (n/3, n%3)) == (transposed(0), transposed(1)) )

unzip3 メソッド
unzip3 メソッドは概ね unzip メソッドと同じですが、2要素のタプルではなく3要素のタプルを扱います。

  case class Person(name: String, age: Int, sex: String)

  val persons = Seq(Person("Alice", 40, "female"),
                    Person("Bob", 30, "male"),
                    Person("Eve", 20, "female"))

  // unzip3 メソッド
  assert( persons.unzip3(p => (p.name, p.age, p.sex)) ==
    (Seq("Alice", "Bob", "Eve"),
     Seq(40, 30, 20),
     Seq("female", "male", "female")) )

unzip3 メソッドも transpose を使って書けると思いますが、unzip の場合と大して変わらないので止めておきます。

前回と次回で多重コレクションに関連するメソッドを試してみました。 少々込み入った処理をしようとしたときに、これらのメソッドを使うと意外と簡潔に書けたことがしばしばあったので、要チェックなメソッド群です。 次回は数学関連のメソッドを試していく予定。

Scalaスケーラブルプログラミング第3版

Scalaスケーラブルプログラミング第3版

Scala の Seq に定義されているメソッドを試す (8) ~多重コレクション~

Scala

Scala の Seq に定義されているメソッドを試すシリーズ(目次)。 今回は Seq の Seq や Seq の Iterator に関連するメソッドを試していきます。 Seq のタプルやタプルの Seq を返すメソッドも試そうと思ったのですが、長くなりそうなのでこれらは次回に。

今回扱うメソッド

// 多重コレクション関連
def flatten[B]: Seq[B]
def flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): Seq[B]

def transpose[B](implicit asTraversable: (A) ⇒ GenTraversableOnce[B]): Seq[Seq[B]]

// Seq の Iterator を返すメソッド
def grouped(size: Int): Iterator[Seq[A]]

def sliding(size: Int): Iterator[Seq[A]]
def sliding(size: Int, step: Int): Iterator[Seq[A]]

def inits: Iterator[Seq[A]]
def tails: Iterator[Seq[A]]

サンプルコード(多重コレクション関連)

まずは多重コレクションに関するメソッド。 flatten メソッドと transpose メソッドは二重の Seq(つまり Seq の Seq)に対して呼び出さないとコンパイル・エラーになります。 flatMap メソッドは直接多重コレクションには関係していませんが、flatten と似ているのでここで扱っています。

flatten メソッド
flatten メソッドは二重の Seq に対して呼び出せ、内側の Seq をバラして一重の Seq にします。

  val metaSeq0 = Seq(
    Seq(1, 2, 3, 4),
    Seq(1, 3, 5, 7),
    Seq(1, 4, 7, 10))

  // flatten メソッド
  assert( metaSeq0.flatten == Seq(1, 2, 3, 4, 1, 3, 5, 7, 1, 4, 7, 10) )

二重 Seq に対して二項演算「+:」で reduce したようなものですかね。 一重の Seq に対して呼び出そうとするとコンパイル・エラーになります。 また、返り値の型から明らかですが、三重の Seq に対して呼び出すと二重の Seq になります(完全に平坦化されるわけではない)。

  val metaSeq1 =
    Seq(
      Seq(
        Seq(0, 1),
        Seq(2, 3)),
      Seq(
        Seq(4, 5),
        Seq(6, 7)))

  assert( metaSeq1.flatten ==
    Seq(
      Seq(0, 1),
      Seq(2, 3),
      Seq(4, 5),
      Seq(6, 7)) )

flatMap メソッド
flatMap メソッドは、map メソッドと flatten メソッドを併せて行うようなメソッドです。 レシーバとなる Seq オブジェクトは一重の Seq で構いません(ここで扱ってますが、引数や返り値に直接多重コレクションは関係してません)。 引数として、各要素を任意の要素型の Seq オブジェクトに変換する関数をとり、返り値はそれらの関数を適用した結果の Seq を(flatten を呼び出したように)平坦化します。

  val intSeq = Seq(1, 2, 3)

  // flatMap メソッド
  val result = intSeq.flatMap(i => Seq.fill(4)(i))  // 同じ値を4つ要素とする Seq を返す
  assert( result == Seq(1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3) )

  // flatMap は map & flatten と同じ
  val f: Int => Seq[Int] = i => Seq.fill(4)(i)
  assert( intSeq.map(f).flatten == intSeq.flatMap(f) )

flatMap メソッドは、filter メソッド、map メソッドとともにモナド関連のメソッドとしても重要です。

transpose メソッド
transpose メソッドは、二重の Seq オブジェクトに対して呼び出せ、二重の Seq を行列と見做したときの転置行列(に対応する二重 Seq)を返します。

  val metaSeq = Seq(
    Seq(1, 2, 3, 4),
    Seq(1, 3, 5, 7),
    Seq(1, 4, 7, 10))

  // transpose メソッド
  assert( metaSeq.transpose ==
    Seq(
      Seq(1, 1, 1),
      Seq(2, 3, 4),
      Seq(3, 5, 7),
      Seq(4, 7, 10)) )

数学にしか使わないんじゃないかという気もしますが、複数の Seq オブジェクトに対して、先頭だけを集めた Seq、2番目だけを集めた Seq、などを取り出したいときにも使えます。

サンプルコード(Seq の Iterator を返すメソッド)

次は Seq オブジェクトを要素とする Iterator オブジェクトを返すメソッド。 assert 文で妥当性検証をしている箇所で、各メソッドの返り値に対して toSeq メソッドを呼び出していますが、これは == で要素が等しいことを検証するためです(Iterator オブジェクトに対しては == でこの検証ができないため)。

grouped メソッド
grouped メソッドは、指定した Int 値の個数ずつ元の Seq の要素を分割した Seq の Iterator を返します。

  val strSeq = Seq("a", "b", "c", "d", "e", "f", "g", "h")

  // grouped メソッド
  assert( strSeq.grouped(3).toSeq ==
    Seq(
      Seq("a", "b", "c"),
      Seq("d", "e", "f"),
      Seq("g", "h")) )  // 要素数が2個

元の Seq の長さによっては、最後の Seq の個数が指定した個数より少なくなることがあります。

sliding メソッド
sliding メソッドには引数を1つとるものと2つとるものがあります。

Int 値1つを引数にとる sliding メソッドは、grouped メソッドと同じように指定した個数ずつ元の Seq オブジェクトの要素を返しますが、grouped メソッドと異なり先頭を1ずつずらして要素をまとめていきます。 したがって、2以上の値を引数に指定すると、要素がいくつかの Seq に重複して含まれます。

  val strSeq = Seq("a", "b", "c", "d", "e")

  // sliding メソッド その1
  assert( strSeq.sliding(3).toSeq ==
    Seq(
      Seq("a", "b", "c"),
      Seq("b", "c", "d"),
      Seq("c", "d", "e")) )

引数1つの sliding メソッドでは、grouped メソッドと異なり全ての Seq の要素数が指定した Int 値となります(ただし、元の Seq オブジェクトの長さより大きい値を引数として指定すると、指定した長さと異なる Seq オブジェクトが返されます)。

Int 値2つを引数にとる sliding メソッドは、1つ目の Int 値はまとめる要素の個数、2つ目の Int 値は先頭をとるときにずらすステップ数です。

  val strSeq = Seq("a", "b", "c", "d", "e", "f", "g", "h")

  // sliding メソッド その2
  assert( strSeq.sliding(3, 2).toSeq ==
    Seq(
      Seq("a", "b", "c"),
      Seq("c", "d", "e"),
      Seq("e", "f", "g"),
      Seq("g", "h")) )

引数を2つとる sliding メソッドでは、grouped メソッドと同じように、最後の Seq オブジェクトの要素数が小さくなる場合があります。 また、第1引数と第2引数が同じ場合は grouped メソッドと同じ内容の Iterator を返します。

  // sliding メソッドの2つの引数が同じなら grouped メソッドと同じ
  assert( strSeq.sliding(3, 3).toSeq == strSeq.grouped(3).toSeq )

tails メソッド
tails メソッドは、元の Seq オブジェクトから始め、その tail、そのまた tail、そのまた tail と、空の Seq オブジェクトになるまで tail を返す Iterator を返します。

  val strSeq = Seq("a", "b", "c", "d", "e")

  // tails メソッド
  assert( strSeq.tails.toSeq ==
    Seq(
      Seq("a", "b", "c", "d", "e"),
      Seq("b", "c", "d", "e"),
      Seq("c", "d", "e"),
      Seq("d", "e"),
      Seq("e"),
      Seq()) )

返される Iterator の要素数は、元の Seq オブジェクトの長さ +1 となります。

ちなみに、tails メソッドの返り値は Seq.iterate や scanRight メソッドを使って以下のように書くことができます:

  val strSeq = Seq("a", "b", "c", "d", "e")

  // Seq.iterate を使って
  assert( strSeq.tails.toSeq == Seq.iterate(strSeq, strSeq.length+1)(_.tail) )

  // scanRight を使って
  assert( strSeq.tails.toSeq == strSeq.scanRight(Seq[String]())(_+:_) )

だからどうだということでもないんですが。

inits メソッド
inits メソッドは、tails メソッドと同じように(逆に?)元の Seq オブジェクトから始めて、init をとっていきます。

  val strSeq = Seq("a", "b", "c", "d", "e")

  // inits メソッド
  assert( strSeq.inits.toSeq ==
    Seq(
      Seq("a", "b", "c", "d", "e"),
      Seq("a", "b", "c", "d"),
      Seq("a", "b", "c"),
      Seq("a", "b"),
      Seq("a"),
      Seq()) )

inits メソッドは Seq.iterate メソッドを使って以下のように書けます。

  val strSeq = Seq("a", "b", "c", "d", "e")

  // Seq.iterate を使って
  assert( strSeq1.inits.toSeq == Seq.iterate(strSeq1, strSeq1.length+1)(_.init) )

inits メソッドの方は scanRight や scanLeft などを使って簡単には書けなさそうですかね。 reverse とか使えば書けるかと思いますが。

今回は多重コレクションに関連するメソッドを試しましたが、次回は似たようなメソッドで、返り値がタプルの Seq、もしくは Seq のタプルとなっているものを試していきます。

Scalaスケーラブルプログラミング第3版

Scalaスケーラブルプログラミング第3版