scala
の編集
Top
/ scala
[
トップ
] [
編集
|
差分
|
バックアップ
|
添付
|
リロード
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
-- 雛形とするページ --
10の質問
ABC予想
AI
AI API
AI プロンプト
AIでつかわれているtransformerのまとめ
AIの話題
ANTLR
ANTLR v3 FAQ よくある質問
ANTLR 独学
ANTLR4 独学
ANTLRでOracleのDDLを解析してみる
ANTLRチュートリアル
AOP
API
ARMマイコン基盤
ATOM SHELL理論
Access VBAメモ
Access-Control-Allow-Origin
AndroidとTensorflow
Android開発
Android開発 入門
AngularJS
Anko
Apache Bench
ArchUnitを学ぶ
Axiosとは
Axis2
BI Publisherで始めるデータ駆動型レポート作成
BPMNの勉強
BackTrack4
Blog from iPhone
Bootstrapとは
BracketName
C3 AI Applications
C3 AI エクスマキナ
CSS備忘録
CentOS
ChatGPTの話題
Chevrotainのパーサメソッド
Chevrotain一覧
Chromeエクステンション
Cocoa Touch Static Library
CoffeeScript
Confluent Control Centerやってみる
C言語でオブジェクト志向な記述方法
DDD ドメイン駆動設計
DDL生成ツール
DJUnit
DMM.comのAPIとか
DOSコマンドメモ
Dashcode
DeepFloyd IF
Dockerが動かない場合の対処
ES2015
Eclipse Monkey
Eclipse Plugin
Eclipseの色設定
Eclipse使いがXCode使い初めて知りたいこと
ElasticMQメモ
Elixir
Emmet
Erlangメモ
ExcelファイルをAIに読ませる
Exceptionを見やすく
Expression Tree
FLEX
FLEX リフレクション
Fisheye
FlashやJavascriptを使った演出
FormattingRules
FrontPage
GAE
GAE Data Store API
GENERAL SQL PARSER JAVA を試してみる
GLOBAL
GPT4ALL
GQL
GUIからMacPortsを管理するアプリケーション - Porticus
Generative Adversarial Networks
Gin JavaScriptで構文解析
Git Blame
GitHubアクションを使ったトロイの木馬のまとめ
GitLab
GitLabRunnerを増やす
GitLabでPlantUML使ってみる
GitLabでプロジェクト管理する
GitLabの機能をそのまま使って認証システム作ったらどこまでできる?
GitLabサーバインストールとメンテ注意事項
GitとAntとSpringとJUnit
Google Cloud Platform
Googleの裏技
Google認定プロジェクトマネージャの勉強メモ
Grails
GraphQL
HTM 階層型時間メモリ
HTML スクレイピング
HTML パース
HTML5
HTML5 Canvas
Hadoop
Help
If Then Maybe プログラミング
Inkscape script
InterWiki
InterWikiName
InterWikiSandBox
JAVAの記事一覧
JBoss
JDBC テーブル一覧を得る
JDBC カラム一覧を得る
JDT eclipse
JGRIB
JHIPSTER JDL
JHIPSTER OpenAPI
JHIPSTER エンティティをフィルタリングする
JHIPSTER6.1.2
JHIPSTERでスマホサイト
JHIPSTERのBLUEPRINTを作る
JHIPSTER一覧
JHipster
JHipster API FirstDepelop
JHipster エンティティを更新する
JHipster7をつかってみる
JHipsterでBuleprintを使いこなす
JHipsterのコード生成を改造
JHipsterのプロジェクトをGitLabでCI/CDする
JHipsterのプロジェクトをデプロイする
JMeter
JOOQとは
JSFとStruts
JSqlParser
Java Closure
Java Compiler API
Java Function
Java SQL Parserを調査する
Java Spring AOP
Java Spriteを設計してみる
Java オブジェクトのダンプ
Java ドラックできる曲線
Java 備忘録
Java 文字化け
Java11以降のJRE
Java7サンプルコード
JavaFx
JavaScriptでパーサを作る Chevrotain
Javaasist 動的にクラスを編集
Javascript グラフィックライブラリ
Javascript コーディングパターン
Javascript界隈
Javassist
JavaでSVG
Javaで関数型で引数をとる
JavaのジェネリクスTip
Javaのラムダ式
Javaの有名なライブラリ紹介
Javaは、IDEのテンプレートを使いこなせばいいよ
Javaプログラマ向けモナド
Javaメモリリーク
Jenkins
Jenkins(Hudson)メモ
Jestとは
Jhipsterマイグレーション
Json Yaml Xml Hash Scala
Kafka REST Proxy さわってみる
Kotolin
LDAPサーバをdockerで立ち上げる
Linux メモ
LiquiBaseとは
Lombok
MDBをコンパクトにするVBA
MQL5 小作品
MT4
MT5 EA
MYSQL
MacTool
Macにしゃべらせる
Mac用のメモ
Mattermostを使ってオンプレミスでチャット環境を作る
Maven
Mementoパターン
MenuBar
NILScript
NetBeanでプロファイル
Network Service Desk Engineer
Node-RED
Node-Red
NumPy
OQL オブジェクト問い合わせ言語
OSコマンドインジェクション
ObjctiveC サウンド
ObjectMapperの備忘録
ObjectiveC NSString
ObjectiveC サーバ
ObjectiveC ターミナル用コマンドを作る
ObjectiveC バックグラウンド
ObjectiveC ワーニング
Oculusアプリの開発
OpenFeint
OpenOffice
OpenResty
Outlook VBA
PHP
POSTGRESQL
Pandas Python Data Analysis Library
PdfBox Java用PDFライブラリ
Plagger
PukiWiki
PukiWiki/1.4
PukiWiki/1.4/Manual
PukiWiki/1.4/Manual/Plugin
PukiWiki/1.4/Manual/Plugin/A-D
PukiWiki/1.4/Manual/Plugin/E-G
PukiWiki/1.4/Manual/Plugin/H-K
PukiWiki/1.4/Manual/Plugin/L-N
PukiWiki/1.4/Manual/Plugin/O-R
PukiWiki/1.4/Manual/Plugin/S-U
PukiWiki/1.4/Manual/Plugin/V-Z
PyHipster
QuartzCore
RAD
REST
RWKV
Rails3
Railsと差分開発についての考察
React.js
React.js モーダル画面
RecentDeleted
RedmineLE
Redshift
Relumeでサイトの骨格を作る
Require.js
Rubycocoa
RubyでScalaをコンパイルするツールをつくる
Rubyアソシエーション認定証
Ruby入門
SCALA REPL
SCALA support tool
SCALAの記事一覧
SELinux
SEO
SEO Yahoo対策
SEO対策一覧
SPAM対策
SQLite
SSH
SVNをJavaで操作
SakuraZencoding
SandBox
Scala / Hadoop
Scala Process exec
Scala 遅延評価
Scala/LiftでSlim3
ScalaSigParser
ScalaWithExcel
Scala チュートリアル
Scalaで3D
ScalaでLisp
ScalaとGroovyのPOJO比較
ScalaのIDEについて
Scala言語を学ぶやさしいツール「Kojo」
Slack API やってみる
SocketAppender
Spring
Spring bootでのテストのTIPS
SpringBootのSTSの新規プロジェクトでるエラーの対応
SpringSecurity SAML
Sqlite
Squirrel
StringTemplate
Stringクラス拡張
TALEND
ThreadLocal
Todo一覧
Trac Lightning
Twitter
UltraEdit
Unityでシューティングゲーム作る際のメモ
VBAでREST通信
VBAのコード
VBAをOpenOffice.org Basicにする
VBAをOpenOffice.org+Basicにする
VPN構築の勉強メモ
VPSやIaaSメモ
VSCodeでRuby開発
VSCodeメモ
VSCode用ChatGptのPlugin
VSCode設定
VirtualBox On Mac
Visual Studio Code プラグイン開発
Vuexとは
WBS管理の弊害
WIN32API
WSDL
Watson
WebDesign探訪
WebLogic フィルタ
WikiEngines
WikiName
WikiWikiWeb
Windows10のPowerShell でキーボードの言語切り替え
WindowsTool
Worker Thread パターン
XBee
XDOCLET
XForms
XPath
XSL
YahooPIPES
Yahooインフォセンター
Yet Another Pragger
YouTuber
YukiWiki
anacondaをcygwinで使う
ansible
antlr snippet
antlr 再入門
antlrと日本語
autoit
automator
bluemix
bootstrap2
bower
ccze Colorize log files on CentOS and Ubuntu using ccze tool
centos7
cglibを使って動的コード生成
cocos2d
cygwin
diff
dockerのローカルイメージをDocker-in-Dockerで参照する
eclipse設定
emacs 備忘録
emacs 文字列置換
emacsをviライクにする
excel tips
excelのdiff
expectで自動化
figmaにプラグインをインストールする
ftp自動化
gemini
generator-jhipster-gql
git diffを使った構成管理の省力化
goをやってみる
grizzly
gulp
homebrew
iPhone Bluetoothプログラミング
iPhone iAd
iPhone 実機テスト手続き
iPhoneでグラフィックのHellowWorld
iPhoneとGmailメール
iPhoneに実機転送
iPhoneプログラミング
iPhoneプログラミング/ビューを理解すればiPhoneアプリの基礎を押さえられる
iPhoneプログラミング一覧
iPhoneプログラミング入門
iPhone開発/Interface Builder Plug-in
iPhone開発/キャプチャの取り方
intra-mart
jQuery.Flickableのメモ
java spring boot 認証 memo
jersey
jhipster-codeにアノテーション追加してみる
jhipsterのテンプレート改造準備
jparsecドキュメント日本語訳
jparsec入門
kafkaの勉強
log4j2の脆弱性
mac diff
mailcowのインストール
memcached
minecraft マイクラ あるきながら、高速ダンジョン作成
mqttの勉強
nginx_lua
nginxのメモ
node_moduleをnpm linkを使って自分用にする
npm
openapi generator
openapi-generatorをコンパイル
openstack
oraclerac
play framework 1.2.5 sample
play! framework
play!framework selenium
playframework テンプレート
postmanとopenapi
prezi プレゼン
pukiwikiで行動管理
pukiwikiに類似したツール
pukiwiki勉強
pukiwiki記事一覧
python
python3のwindowsでの日本語文字化け対応
pythonでseleniumを使う
pythonのテストに使うライブラリ
rails5
reactでポップアップ表示
redmine
ruby on rails 6.0.0
scala
scala 99problem 32~
scala prototype.zip
scala repl
scala sbaz
scala spring
scala/インストール
scalaでまだ不勉強なところ
scalaのインストール
selenium
slack api
spark
spring boot
spring initializerをつかってプロジェクトのひな型をゲットする
spring-test
springboot
springboot env
storybook
sublimetext2
swagger
tracについて
ubuntu
vaadin
vue を typescriptで開発
vue 共通部品作成
vue.js memo
vue.jsとは
vue.jsのデバッグ
vue一覧
webの編集画面のよくあるパターン
windows環境構築
wordpress
xamppについて
•Axis2の本家のスタートガイドによるWebサービスの作り方
【Javascript】【CLIライブラリ】commanderの勉強
【MQL5】KuniRangeBreakoutEA
いまさらながらC++
びっくりする短いコード
アクター
アニメーション
アノテーション
アプリコット
アプリコット PukiWiki
アプリコード
アプリコード林邦行
イラストのエフェクト
インテンショナルプログラミング
カスタマイズjhipster7.9.3イメージ
カブロボ
ガイガーカウンター
クラスとハッシュマップの関係
クラック対策
クロス集計
コマンドラインという概念への考察
コミニュケーション
コード生成
サロゲートキーを使ったテーブル設計
シェルのサンプル
シェルサンプル
スクレイピング
スレッドプログラミングメモ
ソースtoソース変形
ターミナルをAppleScriptで制御
テキストエディタ作成javascriptフレームワーク
テスト用まっさらDBをdockerでたてる
テスト駆動
テレワーク環境の比較
ドット絵
バイオビルダー合成生物学メモ
バグの少ない設計のためのValueObject
パフォーマンスチューニング
フロントエンドのテストの結合テストを減らすには?
プッシュ技術
プログラマーじゃない人に覚えてほしいプログラムのコメントの書き方
プロジェクト管理スプレッドシート
マイクラ 有名ディメンション モッド
マクスウェル方程式
メタ
ラムダ計算について考える
リベリカJava13いいみたい
リモートワークでのプロジェクト注意点
レイアウトツール
ログ解析
世界の構文解析グラマーたち
予定表
予定表/2009-12-14
予定表/2009-12-18
予定表/2009-12-19
予定表/2009-12-22
予定表/2009-12-23
予定表/2009-12-24
事業の心構え
事業計画方針
人工知能とCUDA
人工知能コンペKaggle
仕様書のフォーマットについての考察
他言語サイトサンプル作成
仮説Oracleの罠
作曲と効果音作り
共和分
口コミ
古いRails5を入れる
哲学
大文字小文字変換
学習をHackする
扶養とシステム
投薬のみのガンの治療薬
擬似コーディングのすすめ
放射能対策
数式を扱う
文章を書く
新エネルギー
新年の抱負2010
新技術 プログラム編
日本のゼネコン式IT開発が失敗する理由
最近更新したページ
未来技術/新技術
枯れた技術の水平思考
株価データ
業界の動向
構文解析の記事一覧
正規表現
気象データ
流れるようなインタフェース
管理画面の生成におけるopenapiとJDLなどの考察
細胞の若返り
経済のことをまとめてみる
脆弱性
自分でPlaggerみたいなのを作るためのメモ
論語/学而第一
負荷テスト
販売/デスクトップPC
販売/ノートパソコン
販売/外部ストレージ
起業
酸化グラフェン
開発哲学
電子出版
電子出版の記事一覧
非可換幾何学
顧客分析のデシル分析とRFM分析
DIコンテナについて考える
MP3から携帯着うたを作る方法
[[SCALAの記事一覧]] &topicpath; *はじめに [#c3d68e63] このページは関数脳を作るべく、関数言語を題材にした99個の問題を解くのではなく、 解いてある回答を見て学ぶために作ったページです。 再帰的に解いてあると、関数言語だなーという気分になるのは、じぶんだけでしょうか? まだ、全問といていませんが、極力1日1問のペースで解いていこうとおもっています。 ページが大きくなってきたので、32問目以降は下記のページに記載しています。 [[scala 99problem 32~]] *目次 [#b66f8a7d] #contents こんにちは、みなさんお元気ですか。 このページはプログラミング言語SCALAについてまとめたページです。 Androidアプリケーションの開発やクラウド開発、 そして企業のリソースをWebAPI化するなどの プログラミングには信頼性や資源の多さからJavaが有効だとおもいますが、 SCALAはそのJavaアプリケーションをさらに効率よく開発する可能性を秘めています。 *Scalaとは [#g9395f0f] Scalaは、JVM上で動作するオブジェクト指向+関数型言語で、 Javaとほぼ完全な相互利用が可能な言語です。 これまでの言語の集大成に近い言語です。 そのため、各言語の優れた概念を取り入れているわけです。 軽い気持ちで学ぶと、あちこちの言語の概念の基本を抑えたほうが近道なこともあり、 色々な言語の入門書をわたり歩くはめになります。 作者であるMartin Odersky教授はJavac開発の貢献者であるとともに、 Java5 Genericsの仕様策定にも参加しています。 というわけでSCALAはJava言語と親和性の高い関数型言語です。 コンパイルするとJavaのクラスファイルになるんですよ。 Javaのライブラリは膨大で他の言語に比べて日本語の処理方法がしっかりしています。 そしてコードが簡潔に書けるので生産性が高いといわれています。 たとえばBeanクラスを記述する場合、例は下記に記しますが、3分の1の コーディングですみます。 *Scalaの紹介 [#xa9d618e] http://qcontokyo.com/pdf/qcon_TakashiMiki.pdf **バージョン2.8の説明 [#d92a6240] http://eed3si9n.github.com/scala-collections-doc-ja/collections_0.html **Scala開眼 [#p43ad847] http://www.h7.dion.ne.jp/~samwyn/Scala/scalaindex.htm **Scala Wiki Start [#eccfd0df] 英語のサイトであるが、情報が豊富である。 最初のページは検索のテキストボックス程度が表示されている程度だが、 検索エンジンで気になる単語を入れ検索すると、いろいろとScalaの記事が出てくる。 http://scala.sygneca.com/ **その他の特徴 [#i82a745f] -関数を生成して返す関数を定義できる -配列のパターンマッチング -XMLを簡単に扱える -多重継承ができるので、メソッドを部品のように扱える JavaにはできないことができるのにJavaと親和性が高いのです。 **練習問題 S-99 Ninety Nine Scala Problems [#zc5b14a2] 何らかの練習問題をこなすことで力がつくとおもいます。自分で解くことも大切ですが模範回答から学ぶことも大切です。 このページは下記の S-99 Ninety Nine Scala Problems http://aperiodic.net/phil/scala/s-99/ の回答をつかって学習していくページです。 模範回答をみてえられる知識は実践向きの知識とも言えるかとおもいます。 パズルゲームを解いていくような気分で1日1問を解説していければとおもっています。 **99問題の日本語訳 URL [#h1e5ee9e] http://study-func-prog.blogspot.com/2009/05/scala-s-99-ninety-nine-scala-problems.html *対象者 [#a4017fbd] SCALAのインストールは完了し、HelloWorldを実行し終えた程度の読者を想定 SCALAをやるのは全くのはじめてという方向け SCALAはコンパイルすると、JAVA言語のクラスを生成する関数型言語です。 型推論を行ってくれるので、マスターすれば生産性が向上します。 *趣旨 [#k9b945e2] 有名な練習問題99問が回答付きで英語ながらも存在しているので、 回答をみながら、ポイントをまとめていこうかという趣旨です。 問題自体はリストを処理するAPIを知っている人向けなのですが、 問題が出てくる毎にそのメソッドを紹介していきます。 *参考:リストを操作するAPI [#dc8ce051] https://www.scala-lang.org/docu/files/api/scala/List.html ***ローカルにAPI資料をもってきたい場合 [#t5cff7df] sbazというインストーラからダウンロードします。 名前の由来は「Scala Bazaars」です。 DOSプロンプトで操作します。 rem はDOSのコメント行を意味しています。 rem sbazのあるディレクトリにカレントディレクトリを移します。 cd C:\scala\bin rem sbazを使えるようにします。 sbaz installed rem 一覧を取得します。 sbaz available rem ドキュメントをダウンロードします。 sbaz install scala-devel-docs 下記のフォルダにAPI資料をダウンロードできます。 C:\scala\doc\scala-devel-docs\api *1問 [#c993a2a7] 1問目は、回答を自分の環境で実行させること自体が学びが大きいです。 **手順 [#l78cdce7] -回答をP01.scalaというファイル名で保存します。 ***インタプリタ形式で確認するには、 [#scb13ea3] scalaでインタプリタ形式で :load .\P01.scala と入力すると 読み込んでくれます。 ***確認方法は [#xa5e1ff8] P01.last(List(1,2,3,4,5)) です。 ***最後の要素を取得する [#ffe2eca1] .last **Scala Listクラスのメソッドを全部実行してみてるURL [#zf18b096] Scalaを学び始めていきなりどんなメソッドがあるのかさっぱりわからないと思う、 片っ端からリストクラスを操作するメソッドを試したつわものがいました。 使い方が大体わかるかも。ただしバージョンは2.7ベースな点に注意。 http://kaitenn.blogspot.com/2010/02/scala-list.html **2.8のListのメソッド一覧 [#x7906894] ちなみに2.8のListのメソッド一覧は下記です。 https://www.scala-lang.org/docu/files/api/scala/collection/Traversable.html *2問 [#n5ca2709] 2問とは関係ないのだが、今度はEclipseでSCALAを実行させてみたいとおもう。 そのためには下記のプラグインをインストールすることが必要だ。 Scala IDE for Eclipse http://www.scala-lang.org/node/94 **Scala Eclipse Pluginの導入 [#fe8b9747] Eclipse開いて、「Help -> Install New Software... -> Workwithフォルダに Available Software -> Add Site..」でLocationに「http://www.scala-lang.org/scala-eclipse-plugin」と入れる あとは、直感的にわかるので省略 **確認用メイン [#u8fc4086] 回答をエクリプスから実行するにはメインメソッドが必要ですので、 下記のような実行用のメソッドを用意するといいでしょう。 object HelloScala { def main(args:Array[String]) { println("Hello Scala!") println("P03") println(P03.nth(2,List(1,2,3,4))) System.exit(0) } } **本題の2問目 [#ne66d693] // But pattern matching also makes it easy. def penultimate[T](l: List[T]): T = l match { case e :: _ :: Nil => e case _ :: tail => penultimate(tail) case _ => throw new NoSuchElementException } 1問目と比較してみる def last[T](l: List[T]): T = l match { case e :: Nil => e case _ :: tail => last(tail) case _ => throw new NoSuchElementException } ***scalaは配列要素をパターンマッチできるようだ。 [#p80b5dac] 2問目の最後から2つ目にマッチ case e :: _ :: Nil => e 1問目の最後にマッチ case e :: Nil => e ::は配列の要素間の区切り文字である。 ***配列の長さを取得する [#h772481a] .length ***右からn個の要素を取得する [#n1cb2746] .takeRight(2) ()はapplyメソッドと同等らしいです。 ***先頭を取得する [#z25fced1] .head *3問目 [#k49dbbd9] 回答に (n, l) match { } という構文が使用されている 第一パラメータっぽい変数nがmatch内で使えるようになっている ***n番目の要素を取得する [#gb93f5e2] 配列変数(n) *4問目 [#c6f8d542] ***def内にdefを入れ子にできる [#y1cc836a] 例 def foo = { def bar = { } bar } ***先頭以外の要素 [#o852f411] .tail *5問目 [#ma5248d6] ***配列を逆にする [#r0ba9d89] .reverse **配列を連結する演算子::と::: [#m7f4bb61] 配列を連結する演算子には::と:::があって、知らないと困る ***::の例 [#g9697964] List(1,2,3) :: List(4,5,6) 結果 2番目の配列の先頭に格納される List(List(1,2,3),4,5,6) ***:::の例 [#q33c0004] List(1,2,3) ::: List(4,5,6) 結果 List(1,2,3,4,5,6) ***配列の連結演算子:: [#s5798690] ***match内での先頭とそれ以外の分割(効率はn^2なので小さい配列向き) [#y9c37311] case h :: tail => reverse(tail) ::: List(h) ***Nil=List() と List(1,2)=1::2::Nil [#r3204da6] 配列の書き方で 1 :: 2 と書くとエラーになるが 1 :: 2 :: Nil と書くと List(1,2) として認識される **配列の要素をまずは、初期値を処理し、次からは次の要素と処理結果とを処理させる [#b244a202] ややこしいが、その分応用できる箇所をすっきりと記述できる。 .foldLeft 左からぱたぱた倒れていくような感じの関数で初期値と、 名前なしの関数を与えるようなイメージ -例 (List(2,3,4).foldLeft (1)) {(x,y) => x+y} -結果 10 これは1から4までの数字を合計するというもの まず、1と2が、xとyに格納されて計算結果が自動的に左側のxに格納される 次にxと3が計算され、xに格納 どうようにxと4が計算され結果が出力されるという感じだ。 xとかyとかがなくても、次の書式で対応可能だ。 (List(2,3,4) foldLeft 1) {_+_} ***foldLeft・foldRightは別名があり、それぞれ「/:」「:\」とも書ける。 [#j35ee226] foldLeft は /: とも書けるので次のようにより簡潔に書ける (1 /: List(2,3,4))(_+_) 初期値が先頭にきている感じだ。 ()を閉じ終えてからくる()が、処理。 ***回答を理解できるようになったので解説してみる [#mddb4ff8] というわけで、次の処理内容をみてみると以下のことが理解できる def reverse[T](l: List[T]): List[T] = l.foldLeft(List[T]())((r, h) => h :: r) List[T]()は初期値であり、空の配列である。 最初は空の要素と左の要素が処理され最初の要素がrに格納される 次の要素はhに格納され最初の要素はrなので、(2番目の要素,最初の要素) が格納される。 **応用:Beanを定義する。 [#hf8ee7ab] ここまでは、配列の中身が数値とかだったので、もう少し込み入った情報を扱いたい場合もあるかとおもいますので、Beanの扱いについて説明いたします。 その前にオーバライトの書き方を紹介します。 ***Javaメソッドのオーバライド [#d7458651] defの前にoverrideをつけます。 override def toString="(name:"+name+ " value:"+value+")" **case classを使った定義方法 [#jfa5c6e4] -例 case class FieldValue(name:String , value:String ) { override def toString = "(name:"+name+ " value:"+value+")" } たったの3行です。おそらく1行でもいけるでしょう。 **通常のBeanの設定方法 [#hae76bdb] ***Beanの定義 [#e770c35c] class FieldValue(_name : String , _value : String) { val name = _name val value = _value override def toString="(name:"+name+ " value:"+value+")" } ***コンストラクションを増やしたい場合 [#z7935a70] 例 class FieldValue(_name : String , _value : String) { val name = _name val value = _value override def toString="(name:"+name+ " value:"+value+")" def this(_name:String) = this(_name,null) } ***Beanインスタンスの作成 [#ta18a7e3] val field1 = new FieldValue("key1","data1") val field2 = new FieldValue("key2","data2") val field3 = new FieldValue("key2","data2") val field4 = new FieldValue("key2","data2") ***Beanの配列 [#eea500d5] List(field1,field2,field3,field4) *問6 [#jb8a4b39] 答えは簡単に def isPalindrome[T](l: List[T]): Boolean = l == l.reverse だった。 **scalaのfor文 [#cad712c0] 配列以外でループさせたい場合につかうかもしれない for (x <- (0 to 10)){ println(x) } ***takeWhile [#b6a12347] ちなみにループ中にループを抜けたい場合はtakeWhileをつかう var continue = true for (x <- (1 to 20).takeWhile(e => continue)) { println(x) continue = x < 5 } var continue = true (1 to 20).takeWhile(e => continue).foreach { x => println(x) continue = x < 5 } -ただし、上記の例でバージョン2.7.7では意図した結果になるのに対して、2.8Betaだとcontinueのスコープがずれてしまい、別々の変数とみなされてしまいます。 とりあえず、バクかなとおもって本家にバグ報告してみたところ下記の回答がかえってきました。 **SCALAの本家から回答が帰ってきました。 [#v9d8ed93] this is the result of an intentional change. Range is strict now. one way to get lazy behavior would be to insert toStream: "(1 to 20).toStream.takeWhile". in general, though, mixing for comprehensions and side-effects is discouraged. つまり下記のように(1 to 20)の部分を(1 to 20).toStreamとすればよいようです。 var continue = true for (x <- (1 to 20).toStream.takeWhile(e => continue)) { println(x) continue = x < 5 } **配列の連結 [#lb9151aa] 配列の連結は先頭にしかできないので どうしても末尾にしたい場合は、 reverseをつかって先頭に追加してから、 またreverseでもどしたりする。 **文字列格納用配列の宣言 [#m0b9dc5b] var result :List[String] = List() が正解で var result = List() ......NG Error だと、空配列しか受け付けない配列として宣言したことになるようです。 ***配列の追加 [#of21c1dc] 配列が先頭にしか追加できない result = "a" :: result だとエラーにならないけど result = result :: "a" だとエラーになるってこと ***戻り値のあるメソッドの書き方注意点 [#mc57b072] メソッドの戻り値がある場合は、メソッドの中身を書く際に={中身}とすること そうしないと illegal start of declaration というエラーがかえってきます。 ***キャストの仕方 [#h4071f02] クラスの型を正しく指定しないといけませんので指定します。 BufferedSourceでキャストする方法 .asInstanceOf[BufferedSource]. ***動的変数を持つ関数の作り方 [#a10ec873] 動的変数は try catch の中のプログラムをブロックとして、 あとで追加できるようにする仕組みで、ファイルを閉じるなどの 必ず行うような処理を簡潔に書くことができます。 def 動的関数名(引数)(動的変数 => Unit){ } ***動的変数を持つ関数の使い方 [#ib5c9174] 動的関数名(引数){(動的変数 ) => 処理内容 } **文字列を配列に変換する [#nc5cd2c6] ファイルから読み込んだ文字列の場合、いったん配列にしてやらないといけない だから文字列を配列に変換するメソッドをつくってみました。 def to_a(text:String):List[String] ={ var result :List[String] = List() var len = text.length; for (x <- (0 to text.length -1)){ result = text.substring(len-x-1,len-x) :: result } result } 別解:JavaのtoCharArrayをつかう例。これだけでもいいけどArray型になってしまうため、型変換メソッドも用意しました。 //ArrayをList配列に変換します。 def toListoReverse(array:Array[Char]):List[Char]={ var result :List[Char] = List() array.foreach{ x=>result = x :: result } result } //文字列を配列に変換します。 def toList(string:String):List[Char]={ toListoReverse(string.toCharArray).reverse } **ファイルの読み込みを動的変数で簡潔にする [#s98a5e3d] ファイルの読み込みはclose処理をいれなきゃいけないのですが、 動的関数をつかえば、簡潔に表現できます。 import scala.io.Source import scala.io.BufferedSource import java.io._ // ファイルの読み込みを動的変数で簡潔にする def read(path: String)(block: Source => Unit) ={ var fis :FileInputStream =null var sou :Source =null try { fis= new FileInputStream(path) sou= Source.fromInputStream(fis) block(sou) }finally{ sou.asInstanceOf[BufferedSource].close fis.close } } //readメソッドの使い方はこんな感じ read("sample.txt"){(in:Source) => for(line <- in.getLines){ println(line.stripLineEnd) } } ファイルをcloseする箇所が省けているのがわかります。 ***応用:ファイルの内容を一気に配列化するメソッド [#re0a257f] //ファイルをすべて読み配列で返します。 def readAll(path: String):List[String]={ var result :List[String] = List() read(path){(in:Source) => for(line <- in.getLines){ result = line.stripLineEnd :: result } } result.reverse } //使い方 readAll("sample.txt").foreach(println _) とってもシンプルになりました。 *問07 [#u51f94f7] **scala.Anyとは [#sea29c93] Scala のすべてのクラスの継承元となる基底クラス (Int、Float、Double などの型やその他の数値型) は scala.Any 型です。 **入れ子状態になっている配列の入れ子を解消してフラットな配列にする [#pfa20fee] flatMapをつかいます。flatMapは基礎的メソッドです。 def flatten(l: List[Any]): List[Any] = l flatMap { case l: List[_] => flatten(l) case e => List(e) } -flatmapもmapもArray()で行えば、Arrayをかえしますし、Listで行えばListをかえします。 - => 記号は左側にブロック変数を指定できるので重要です。 - さらにブロック変数はcaseによってリストのパターンごとの処理が可能になっています。 *問08 [#e36ac1fa] **値が一致する要素を削除する [#v5207dcb] match処理内のcase処理部分でつかいます。 tail.dropWhile(_ == e) 普通に式を評価しようとするとvalue dropwhile is not a member of Listとエラーになります。 *問09 [#m0f568a4] Haskellでいうところのgroupメソッドとかなり類似した関数のようですね。 最近、下記のようなところでもりあがっているのを知りました。 http://wordprogress.org/archives/366 それはさておき、ここの回答でつかわれているテクニックに焦点をあててみていきましょう。 **多重代入 [#r04dde2d] ScalaもRubyのように多重代入ができるんですねぇ。 scala> val (aa,bb)=(11,22) aa: Int = 11 bb: Int = 22 ***List形式の場合の多重代入 [#tfc30d30] scala> var list = List(1,2,3) list: List[Int] = List(1, 2, 3) scala> var List(aa,bb,cc)=list aa: Int = 1 bb: Int = 2 cc: Int = 3 ***一致するシンボルと、それ以降を分離する。span [#b07ff58f] spanをつかいます。 -例 l.span(_ == l.head) scala> var l = List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e) scala> l.span(_ == l.head) res16: (List[Symbol], List[Symbol]) = (List('a, 'a, 'a, 'a),List('b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)) *問10 [#d9f67211] えーっとここの問10の記事でバッチファイル作りなど、いろいろ脱線した記事を書いているので、無視してもらっていいです。 前回で定義したメソッドと連携して最小限のメソッド実装で問題を解いていきます そのためには前回定義したメソッドをimportします。 import P09.pack インポートするためには参照元の.scalaファイルがコンパイルされている必要があります。 さもなくば、下記のエラーが出ます。 P09 is not a member of problem というわけで、 scalac P09.scala でコンパイルすればいいんですが、 今後プロジェクトでこの99の問題をコンパイルし続けるとディレクトリ内はソースとクラスファイルでごちゃごちゃになってしまいます。 それを防ぐためには、ソースファイルとクラスファイルの出力先を分けたたほうがいいですし、 そして問題の回答としてできてくる99個のファイルは一つのパッケージにしなきゃつらいですね。 となると、package化の必要があります。と、なると -フォルダ構成は プロジェクト名 +---src +---problem <---パッケージ名 +---target +classes <----出力フォルダ で、いちいちscalacのオプションを書くのは面倒なのでバッチファイルをつくりました。 拡張子の.scalaは省略してもいいようにしてあります。 --ただし、jarファイルのクラスパスをまとめてコンパイルするにはさらなるクラスパスの追加が必要です。 **バッチファイルでの特定の拡張だけのパスを集める最小限的のサンプル [#r054caaa] @echo off set CP=. set BASE=. setlocal ENABLEDELAYEDEXPANSION for %%f in (%BASE%\*.jar) do set CP=!CP!;%%f echo %CP% ---setlocalはこのバッチファイルだけで有効なことを意味します。 ---ENABLEDELAYEDEXPANSIONを指定しないと、for文が並列で評価されてしまい、クラスパスが連結されません。 ---forには /R というサブディレクトリも検索対象にするオプションがあるはずですが、なぜか自分の環境(XP)では動作しませんでした。 **クラスパスの指定に偽ワイルドカード [#z3e0e43b] Java SE 6 では、クラスパスの指定に偽ワイルドカードが使えるようになるようです。 なんで偽かっていうと ---java -cp ./*.jar;./lib/*.jar のように *.jar とか書くとダメ ---java -cp ./*;./lib/* のみ対応 設定箇所はプロジェクトのディレクトリです。 -compile.bat REM プロジェクトのディレクトリを設定 SET PROJECT=C:\scala\problem SET SRC=%PROJECT%\src SET CLASS=%PROJECT%\bin scalac -sourcepath %SRC% -classpath %CLASS% -d %CLASS% %SRC%\%1.scala -実行方法 compile.bat problem\P09 **ビルドツールの出番 [#j9107d6c] でもimportするということは、ファイル同士に依存関係が出てくるということです。 ということは、 いまは例題を1から順番にやっているだけなので順番にコンパイルしていけばいいのですが、 業務でつかうとなれば、ビルドツールのANTまたは、MAVENをつかったほうがよさそうです。 **ビルドツールMAVEN [#p35eafcc] ダウンロード http://maven.apache.org/download.html 仮に解凍したディレクトリの名称をmavenに変更して下記に設置したとします。 C:\maven -環境変数を設定します。 -M2_HOME=C:\maven -M2=%M2_HOME%\bin -PATH=%PATH%;%M2% -mavenの環境変数設定の確認 mvn --version -mvnでscalaをつかうためのおまじない --参考 ---http://codezine.jp/article/detail/4476?p=2 ---http://akisute.com/2009/11/maven2scalahello-world.html 参考サイトによればできたプロジェクトにpom.xmlがありますが、プラグインのバージョンを合わせるためこれを修正しなくてはなりませんが、 お決まりの操作なので バッチファイルとrubyでつくったスクリプトを用意しました。 なんで、rubyかって?単に簡潔に書けそうな気がしたからです。 --プロジェクト作成バッチファイル **mkprj.bat [#wec0a917] SET PROJECT=%1 SET PACKAGE=%2 SET RUBYSCRIPT=c:\scala\bin\scalaproject.rb @echo off if exist %PROJECT% GOTO PROCESS1 SET CREATE=org.apache.maven.plugins:maven-archetype-plugin:1.0-alpha-7:create SET PARAM= -DarchetypeGroupId=org.scala-tools.archetypes SET PARAM=%PARAM% -DarchetypeArtifactId=scala-archetype-simple SET PARAM=%PARAM% -DarchetypeVersion=1.2 SET PARAM=%PARAM% -DremoteRepositories=http://scala-tools.org/repo-releases mvn %CREATE% %PARAM% -DgroupId=%PACKAGE% -DartifactId=%PROJECT% :PROCESS1 if exist %PROJECT%\pom.xml.bat GOTO PROCESS2 ruby %RUBYSCRIPT% c:\scala\bin\scalaproject.rb %PROJECT% %PACKAGE% %3 :PROCESS2 --使い方 ---したに示したテキストファイル処理Rubyスクリプトがあることが前提のバッチファイルです。 ---プロジェクトフォルダがないことが前提です。 cd プロジェクトの親ディレクトリ mkprj プロジェクト名 パッケージ名 合わせたいscalaバージョン --例 mkprj problem99 problem 2.7.7 **scalaproject.rb [#qfa58e1d] #プロジェクト名を第一引数にとります。 #パッケージ名を第2引数にとります。 #バージョンを第3引数にとります。 puts "argv[0]:"+ARGV[1] projectname =ARGV[1] filename = projectname + "\\pom.xml" file = open(filename) # 保存用バッファ buffer = file.read().split("\n"); file.close # バックアップ用ファイルを開く bkup = File.open(filename + ".bak" , "w"); # ファイルから読み込んでバックアップに書き込む bkup.write(buffer); bkup.close # ファイルを書き込みモードで開き直す file = File.open(filename , "w"); #処理 cnt = 0 buffer.each {|line| cnt = cnt + 1 #64行目から66行目をカットします。 if !(64..66).include?(cnt) #以前のバージョン2.7.0を今のバージョンに置き換えます。 file.puts line.gsub("2\.7\.0",ARGV[3]) #初期値では if cnt==94 heredoc= <<EOS <!-- このlaunchers要素を新規に作る。idとmainClassは必須。 --> <launchers> <launcher> <id>app</id> <mainClass>PACKAGE.App</mainClass> <!-- 以下、任意要素。 args と jvmArgs を指定できます。 --> <!-- <args> <arg>arg1</arg> </args> <jvmArgs> <jvmArg>-Xmx128m</jvmArg> <jvmArg>-Djava.library.path=...</jvmArg> </jvmArgs> --> </launcher> </launchers> EOS file.puts heredoc.gsub("PACKAGE",ARGV[2]) end end } file.close **実行 [#c825ff25] mkprj.bat problem99 problem 2.7.7 はなぜかコンパイルし終わると停止するので2度実行しています。 mkprj.bat problem99 problem 2.7.7 mkprj.bat problem99 problem 2.7.7 cd problem99 mvn scala:run **問09をMavenで実行させてみる。 [#i8df2544] -P09.scala package problem object P09 { def pack[T](l: List[T]): List[List[T]] = { if (l.isEmpty) List(List()) else { val (packed, next) = l.span(_ == l.head) if (next == Nil) List(packed) else packed :: pack(next) } } } -P10.scala package problem object P10 { import problem.P09.pack def encode[T](l: List[T]): List[(Int, T)] = pack(l).map(e => (e.length, e.head)) } -App.scala 改 package problem /** * Hello world! * */ object App extends Application { println( "Hello World!" ) import problem.P10._ println(encode(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e))) } **実行 [#tf761882] mvn scala:run とりあえず、ソースをかけば、コンパイルから実行までやってくれるのがわかった。 さすがに、scalecを直接やるよりは遅い ***クラスファイルの出力先 [#t56c78be] プロジェクトフォルダ\target\classes ***インタプリタ形式でscalaを動かしたい場合 [#eccca17d] cd プロジェクトフォルダ\target\classes scala *問11 [#y2180116] **単純な括弧、たとえば、(1,2)の要素を取得する [#nb895eea] 今まで、List型の要素取得方法を学んだ scala> List(1,2)(1) res12: Int = 2 しかし、同様の操作を上記のListを省いた形式にあてはめようとするとえらーになる。 scala> (1,2)(1) <console>:7: error: scala.Tuple2.apply[Int, Int](1, 2) of type (Int, Int) does not take parameters ***単なる括弧の要素を取得する方法 [#p3f396f6] scala> (1,2)._1 res11: Int = 1 --この単なる括弧の正体はscala.Tuple2である。 scala> scala.Tuple2.apply[Int, Int](1, 2) == (1,2) res16: Boolean = true 引数の型の数だけTupleクラスが用意されていて、APIを見る限り22個までは用意してあるらしい -22個の例 scala> (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22) res22: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22) 正常に解釈される -23個の例 scala> (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23) <console>:7: error: value Tuple23 is not a member of package scala (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23) 宣言されていないのでエラーとなった。 *問12 [#vba60999] **List.make(2,'a)はList('a,'a) [#v18c1998] **これまでの問題で定義してきたメソッドをあたかもListのビルトインメソッドのように扱う [#bbf78db3] 問題文では、decode(List( (4, 'a), (1, 'b), (2, 'c), (2, 'a), (1, 'd), (4, 'e))) であったが、これを -List((4, 'a), (1, 'b), (2, 'c), (2, 'a), (1, 'd), (4, 'e)).decode で答えが出るようにするには、 case class P12[T](val nums : List[(Int, T)]){ def decode:List[T] = nums.flatMap(e => List.make(e._1, e._2)) } implicit def xxx[T]( num:List[(Int, T)]) = P12(num) -対比のため掲載するが、もとの回答ではつぎのようになる object P12 { def decode[T](l: List[(Int, T)]): List[T] = l.flatMap(e => List.make(e._1, e._2)) } -ポイント --case classでは classで引数をとるようになっており、defの引数が一つ減っている。 *問13 [#jdfa5258] **spanの結果を多重代入する [#y5b22cf6] val (packed, next) = l.span(_ == l.head) *問14 [#t5c21c38] **flatMapを使った方法を思いつくかという問題 [#p995fdd9] #areaedit *問15 [#v7bc29a2] **List.make(n, _)をつかって要素を増やした記述 [#q74067a4] def drop[T](n: Int, l: List[T]): List[T] = { def dropR(c: Int, curList: List[T]): List[T] = (c, curList) match { case (_, Nil) => Nil case (1, _ :: tail) => dropR(n, tail) case (_, e :: tail) => e :: dropR(c - 1, tail) } dropR(n, l) } 回答をみて気がつくのは、defの定義方法である。通常{}でくくるかとおもうが、 いきなり( )表現をつかっている。一つの配列からつくられる高階関数内に処理を書けるからだとおもう。 case文の使い方で気がつくことは、eとtailである、この2つは、どこにも定義や代入の記述がないことをみると、予約されている変数だろう。パターンマッチの書き方も()に応じて用意してあるのだろう。たしか()はTuple2だったはずだ。 #areaedit(end) #areaedit *問16 [#mf5b3ecb] **この問題の回答例1番目で学べるのはカウンターを使って周期的にcase文を選択させていることが学べます。 [#w54f70f2] **zipWithIndex [#v99716b0] Rubyでのeach_with_indexみたいにインデックス番号付きに変換します。 ***例文 [#wd42b26d] List(2, 3, 5).zipWithIndex.foreach(t => println(t._2 + ":" + t._1)) for ((d, i) <- List(2, 5, 6).zipWithIndex) {println(i + ":" + d)} List(7, 3, 1).zipWithIndex.foreach{case (d, i) => println(i + ":" + d)} **filter [#ee114a99] 条件式に一致する要素を抽出します。 def drop[T](n: Int, l: List[T]): List[T] = l.zipWithIndex.filter(v => (v._2 + 1) % n != 0).map(_._1) } #areaedit(end) *問17 [#g18f5769] **splitAtというビルトインメソッドで分割する例 [#p6015899] -例 def split[T](n: Int, l: List[T]): (List[T], List[T]) = l.splitAt(3) -例 takeとdropをつかって先頭と末尾を分割し取得する例 def split[T](n: Int, l: List[T]): (List[T], List[T]) = (l.take(n), l.drop(n)) #areaedit *問18 [#bfd8a868] slice関数を使った回答が一番簡単な問題です。 def slice[T](start: Int, end: Int, l: List[T]): List[T] = l.slice(start, end) #areaedit(end) #areaedit *問19 [#k6bcc473] dropとtakeを使って:::で連結することで、rotateを実現しています。 #areaedit(end) #areaedit *問20 [#t3f24544] 問17でも使った、spiltAtとmatchを使って解くと解ける問題 #areaedit(end) #areaedit *問21 [#t3f24544] これも問17でも使った、spiltAtとmatchを使って解くと解ける問題 spiltAtを使ってからmatchを使うとpreとpostに分割されている。 そこで、 case (pre, post) => と、書きます。 #areaedit(end) *問22 [#v30bba7a] #areaedit 組み込みの変数にRangeが用意されていますが、第二引数未満の整数のリストを作成するようです。 def range(start: Int, end: Int): List[Int] = List.range(start, end + 1) #areaedit(end) *問23 [#lae006e4] #areaedit 乱数の使い方を知っていると解ける (new util.Random).nextInt(l.length) #areaedit(end) *問24 [#mfb2e24e] #areaedit 配列を生成するには下記のようにRangeを使うとよい List.range(1, max + 1) #areaedit(end) *問25 [#s702653f] #areaedit mutable array のupdateを使う #areaedit(end) *問26 [#yfe9b244] #areaedit sublist@を使う // P26 (**) Generate the combinations of K distinct objects chosen from the N // elements of a list. // In how many ways can a committee of 3 be chosen from a group of 12 // people? We all know that there are C(12,3) = 220 possibilities (C(N,K) // denotes the well-known binomial coefficient). For pure mathematicians, // this result may be great. But we want to really generate all the possibilities. // // Example: // scala> combinations(3, List('a, 'b, 'c, 'd, 'e, 'f)) // res0: List[List[Symbol]] = List(List('a, 'b, 'c), List('a, 'b, 'd), List('a, 'b, 'e), ... object P26 { def combinations[T](n: Int, l: List[T]): List[List[T]] = { // flatMapSublists is like list.flatMap, but instead of passing each element // to the function, it passes successive sublists of L. def flatMapSublists[U](l: List[T], f: (List[T]) => List[U]): List[U] = l match { case Nil => Nil case sublist@(_ :: tail) => f(sublist) ::: flatMapSublists(tail, f) } if (n == 0) List(Nil) else flatMapSublists(l, (sl) => combinations(n - 1, sl.tail).map((c) => sl.head :: c)) } } **難しい記述 [#p0dc7cf4] -def flatMapSublists[U](l: List[T], f: (List[T]) => List[U]): List[U] の[U]の書き方 -sublist@の書き方 -slの定義について #areaedit(end) *問27 [#f0a6d1f6] #areaedit すでに問題26で得ている解法というか、メソッドを使えば、この問題27を単純化できることに気がつく object P27 { import P26.combinations def group3[T](l: List[T]): List[List[List[T]]] = for { a <- combinations(2, l) noA = l -- a b <- combinations(3, noA) } yield List(a, b, noA -- b) def group[T](ns: List[Int], l: List[T]): List[List[List[T]]] = ns match { case Nil => List(Nil) case n :: ns => combinations(n, l).flatMap(c => group(ns, l -- c).map(rest => c :: rest)) } } **配列の組み合わせによるfor文 [#m087461b] scalaではfor文は配列の要素をループのカウントがわりに用いることができる。 **yield文 [#zca5424d] for文のあとに記述することで、 for文のループ中の要素をyield文中のプログラムを実行することが可能です。 ** --表記 [#d0d5cd6c] noA = l -- a 配列lから、配列aの要素を除いたモノを返す #areaedit(end) *問28 [#pb5e47d7] #areaedit slacaの配列のソートはsortメソッドが用意されています。 このsortメソッドに比較コードを書くことでsortが実施されます。 比較コードには、scala独特の _ で比較対象の要素を示すことが可能です。 問題bの方は、既に問題10で作成した、要素の長さの配列を得るメソッドを活用します。 既に作った関数をうまく使うことができるかどうかという問題でもあるわけですね。 #areaedit(end) *問29 [#va10fb0e] 素数を扱う問題で 7.isPrime と記述できるなんて、数値がオブジェクトでありなおかつ、そのメソッドを定義できるということですよね。 Scala言語がいかに洗練された言語かがわかります。 class S99Int(val start: Int) { def isPrime = primes.takeWhile(_ <= Math.sqrt(start)).forall(start % _ != 0) } object S99Int { def primes: Stream[Int] = Stream.cons(2, Stream.from(3, 2).filter(_.isPrime)) } 上記のコードを2.8.0 RC3で実行してみたところエラーが出ました。 <console>:7: error: not found: value primes (start > 1) && (primes takeWhile { _ <= Math.sqrt(start) } forall { start % _ != 0 }) となってしまいました。
spamではない場合はチェックをいれてください。
タイムスタンプを変更しない
[[SCALAの記事一覧]] &topicpath; *はじめに [#c3d68e63] このページは関数脳を作るべく、関数言語を題材にした99個の問題を解くのではなく、 解いてある回答を見て学ぶために作ったページです。 再帰的に解いてあると、関数言語だなーという気分になるのは、じぶんだけでしょうか? まだ、全問といていませんが、極力1日1問のペースで解いていこうとおもっています。 ページが大きくなってきたので、32問目以降は下記のページに記載しています。 [[scala 99problem 32~]] *目次 [#b66f8a7d] #contents こんにちは、みなさんお元気ですか。 このページはプログラミング言語SCALAについてまとめたページです。 Androidアプリケーションの開発やクラウド開発、 そして企業のリソースをWebAPI化するなどの プログラミングには信頼性や資源の多さからJavaが有効だとおもいますが、 SCALAはそのJavaアプリケーションをさらに効率よく開発する可能性を秘めています。 *Scalaとは [#g9395f0f] Scalaは、JVM上で動作するオブジェクト指向+関数型言語で、 Javaとほぼ完全な相互利用が可能な言語です。 これまでの言語の集大成に近い言語です。 そのため、各言語の優れた概念を取り入れているわけです。 軽い気持ちで学ぶと、あちこちの言語の概念の基本を抑えたほうが近道なこともあり、 色々な言語の入門書をわたり歩くはめになります。 作者であるMartin Odersky教授はJavac開発の貢献者であるとともに、 Java5 Genericsの仕様策定にも参加しています。 というわけでSCALAはJava言語と親和性の高い関数型言語です。 コンパイルするとJavaのクラスファイルになるんですよ。 Javaのライブラリは膨大で他の言語に比べて日本語の処理方法がしっかりしています。 そしてコードが簡潔に書けるので生産性が高いといわれています。 たとえばBeanクラスを記述する場合、例は下記に記しますが、3分の1の コーディングですみます。 *Scalaの紹介 [#xa9d618e] http://qcontokyo.com/pdf/qcon_TakashiMiki.pdf **バージョン2.8の説明 [#d92a6240] http://eed3si9n.github.com/scala-collections-doc-ja/collections_0.html **Scala開眼 [#p43ad847] http://www.h7.dion.ne.jp/~samwyn/Scala/scalaindex.htm **Scala Wiki Start [#eccfd0df] 英語のサイトであるが、情報が豊富である。 最初のページは検索のテキストボックス程度が表示されている程度だが、 検索エンジンで気になる単語を入れ検索すると、いろいろとScalaの記事が出てくる。 http://scala.sygneca.com/ **その他の特徴 [#i82a745f] -関数を生成して返す関数を定義できる -配列のパターンマッチング -XMLを簡単に扱える -多重継承ができるので、メソッドを部品のように扱える JavaにはできないことができるのにJavaと親和性が高いのです。 **練習問題 S-99 Ninety Nine Scala Problems [#zc5b14a2] 何らかの練習問題をこなすことで力がつくとおもいます。自分で解くことも大切ですが模範回答から学ぶことも大切です。 このページは下記の S-99 Ninety Nine Scala Problems http://aperiodic.net/phil/scala/s-99/ の回答をつかって学習していくページです。 模範回答をみてえられる知識は実践向きの知識とも言えるかとおもいます。 パズルゲームを解いていくような気分で1日1問を解説していければとおもっています。 **99問題の日本語訳 URL [#h1e5ee9e] http://study-func-prog.blogspot.com/2009/05/scala-s-99-ninety-nine-scala-problems.html *対象者 [#a4017fbd] SCALAのインストールは完了し、HelloWorldを実行し終えた程度の読者を想定 SCALAをやるのは全くのはじめてという方向け SCALAはコンパイルすると、JAVA言語のクラスを生成する関数型言語です。 型推論を行ってくれるので、マスターすれば生産性が向上します。 *趣旨 [#k9b945e2] 有名な練習問題99問が回答付きで英語ながらも存在しているので、 回答をみながら、ポイントをまとめていこうかという趣旨です。 問題自体はリストを処理するAPIを知っている人向けなのですが、 問題が出てくる毎にそのメソッドを紹介していきます。 *参考:リストを操作するAPI [#dc8ce051] https://www.scala-lang.org/docu/files/api/scala/List.html ***ローカルにAPI資料をもってきたい場合 [#t5cff7df] sbazというインストーラからダウンロードします。 名前の由来は「Scala Bazaars」です。 DOSプロンプトで操作します。 rem はDOSのコメント行を意味しています。 rem sbazのあるディレクトリにカレントディレクトリを移します。 cd C:\scala\bin rem sbazを使えるようにします。 sbaz installed rem 一覧を取得します。 sbaz available rem ドキュメントをダウンロードします。 sbaz install scala-devel-docs 下記のフォルダにAPI資料をダウンロードできます。 C:\scala\doc\scala-devel-docs\api *1問 [#c993a2a7] 1問目は、回答を自分の環境で実行させること自体が学びが大きいです。 **手順 [#l78cdce7] -回答をP01.scalaというファイル名で保存します。 ***インタプリタ形式で確認するには、 [#scb13ea3] scalaでインタプリタ形式で :load .\P01.scala と入力すると 読み込んでくれます。 ***確認方法は [#xa5e1ff8] P01.last(List(1,2,3,4,5)) です。 ***最後の要素を取得する [#ffe2eca1] .last **Scala Listクラスのメソッドを全部実行してみてるURL [#zf18b096] Scalaを学び始めていきなりどんなメソッドがあるのかさっぱりわからないと思う、 片っ端からリストクラスを操作するメソッドを試したつわものがいました。 使い方が大体わかるかも。ただしバージョンは2.7ベースな点に注意。 http://kaitenn.blogspot.com/2010/02/scala-list.html **2.8のListのメソッド一覧 [#x7906894] ちなみに2.8のListのメソッド一覧は下記です。 https://www.scala-lang.org/docu/files/api/scala/collection/Traversable.html *2問 [#n5ca2709] 2問とは関係ないのだが、今度はEclipseでSCALAを実行させてみたいとおもう。 そのためには下記のプラグインをインストールすることが必要だ。 Scala IDE for Eclipse http://www.scala-lang.org/node/94 **Scala Eclipse Pluginの導入 [#fe8b9747] Eclipse開いて、「Help -> Install New Software... -> Workwithフォルダに Available Software -> Add Site..」でLocationに「http://www.scala-lang.org/scala-eclipse-plugin」と入れる あとは、直感的にわかるので省略 **確認用メイン [#u8fc4086] 回答をエクリプスから実行するにはメインメソッドが必要ですので、 下記のような実行用のメソッドを用意するといいでしょう。 object HelloScala { def main(args:Array[String]) { println("Hello Scala!") println("P03") println(P03.nth(2,List(1,2,3,4))) System.exit(0) } } **本題の2問目 [#ne66d693] // But pattern matching also makes it easy. def penultimate[T](l: List[T]): T = l match { case e :: _ :: Nil => e case _ :: tail => penultimate(tail) case _ => throw new NoSuchElementException } 1問目と比較してみる def last[T](l: List[T]): T = l match { case e :: Nil => e case _ :: tail => last(tail) case _ => throw new NoSuchElementException } ***scalaは配列要素をパターンマッチできるようだ。 [#p80b5dac] 2問目の最後から2つ目にマッチ case e :: _ :: Nil => e 1問目の最後にマッチ case e :: Nil => e ::は配列の要素間の区切り文字である。 ***配列の長さを取得する [#h772481a] .length ***右からn個の要素を取得する [#n1cb2746] .takeRight(2) ()はapplyメソッドと同等らしいです。 ***先頭を取得する [#z25fced1] .head *3問目 [#k49dbbd9] 回答に (n, l) match { } という構文が使用されている 第一パラメータっぽい変数nがmatch内で使えるようになっている ***n番目の要素を取得する [#gb93f5e2] 配列変数(n) *4問目 [#c6f8d542] ***def内にdefを入れ子にできる [#y1cc836a] 例 def foo = { def bar = { } bar } ***先頭以外の要素 [#o852f411] .tail *5問目 [#ma5248d6] ***配列を逆にする [#r0ba9d89] .reverse **配列を連結する演算子::と::: [#m7f4bb61] 配列を連結する演算子には::と:::があって、知らないと困る ***::の例 [#g9697964] List(1,2,3) :: List(4,5,6) 結果 2番目の配列の先頭に格納される List(List(1,2,3),4,5,6) ***:::の例 [#q33c0004] List(1,2,3) ::: List(4,5,6) 結果 List(1,2,3,4,5,6) ***配列の連結演算子:: [#s5798690] ***match内での先頭とそれ以外の分割(効率はn^2なので小さい配列向き) [#y9c37311] case h :: tail => reverse(tail) ::: List(h) ***Nil=List() と List(1,2)=1::2::Nil [#r3204da6] 配列の書き方で 1 :: 2 と書くとエラーになるが 1 :: 2 :: Nil と書くと List(1,2) として認識される **配列の要素をまずは、初期値を処理し、次からは次の要素と処理結果とを処理させる [#b244a202] ややこしいが、その分応用できる箇所をすっきりと記述できる。 .foldLeft 左からぱたぱた倒れていくような感じの関数で初期値と、 名前なしの関数を与えるようなイメージ -例 (List(2,3,4).foldLeft (1)) {(x,y) => x+y} -結果 10 これは1から4までの数字を合計するというもの まず、1と2が、xとyに格納されて計算結果が自動的に左側のxに格納される 次にxと3が計算され、xに格納 どうようにxと4が計算され結果が出力されるという感じだ。 xとかyとかがなくても、次の書式で対応可能だ。 (List(2,3,4) foldLeft 1) {_+_} ***foldLeft・foldRightは別名があり、それぞれ「/:」「:\」とも書ける。 [#j35ee226] foldLeft は /: とも書けるので次のようにより簡潔に書ける (1 /: List(2,3,4))(_+_) 初期値が先頭にきている感じだ。 ()を閉じ終えてからくる()が、処理。 ***回答を理解できるようになったので解説してみる [#mddb4ff8] というわけで、次の処理内容をみてみると以下のことが理解できる def reverse[T](l: List[T]): List[T] = l.foldLeft(List[T]())((r, h) => h :: r) List[T]()は初期値であり、空の配列である。 最初は空の要素と左の要素が処理され最初の要素がrに格納される 次の要素はhに格納され最初の要素はrなので、(2番目の要素,最初の要素) が格納される。 **応用:Beanを定義する。 [#hf8ee7ab] ここまでは、配列の中身が数値とかだったので、もう少し込み入った情報を扱いたい場合もあるかとおもいますので、Beanの扱いについて説明いたします。 その前にオーバライトの書き方を紹介します。 ***Javaメソッドのオーバライド [#d7458651] defの前にoverrideをつけます。 override def toString="(name:"+name+ " value:"+value+")" **case classを使った定義方法 [#jfa5c6e4] -例 case class FieldValue(name:String , value:String ) { override def toString = "(name:"+name+ " value:"+value+")" } たったの3行です。おそらく1行でもいけるでしょう。 **通常のBeanの設定方法 [#hae76bdb] ***Beanの定義 [#e770c35c] class FieldValue(_name : String , _value : String) { val name = _name val value = _value override def toString="(name:"+name+ " value:"+value+")" } ***コンストラクションを増やしたい場合 [#z7935a70] 例 class FieldValue(_name : String , _value : String) { val name = _name val value = _value override def toString="(name:"+name+ " value:"+value+")" def this(_name:String) = this(_name,null) } ***Beanインスタンスの作成 [#ta18a7e3] val field1 = new FieldValue("key1","data1") val field2 = new FieldValue("key2","data2") val field3 = new FieldValue("key2","data2") val field4 = new FieldValue("key2","data2") ***Beanの配列 [#eea500d5] List(field1,field2,field3,field4) *問6 [#jb8a4b39] 答えは簡単に def isPalindrome[T](l: List[T]): Boolean = l == l.reverse だった。 **scalaのfor文 [#cad712c0] 配列以外でループさせたい場合につかうかもしれない for (x <- (0 to 10)){ println(x) } ***takeWhile [#b6a12347] ちなみにループ中にループを抜けたい場合はtakeWhileをつかう var continue = true for (x <- (1 to 20).takeWhile(e => continue)) { println(x) continue = x < 5 } var continue = true (1 to 20).takeWhile(e => continue).foreach { x => println(x) continue = x < 5 } -ただし、上記の例でバージョン2.7.7では意図した結果になるのに対して、2.8Betaだとcontinueのスコープがずれてしまい、別々の変数とみなされてしまいます。 とりあえず、バクかなとおもって本家にバグ報告してみたところ下記の回答がかえってきました。 **SCALAの本家から回答が帰ってきました。 [#v9d8ed93] this is the result of an intentional change. Range is strict now. one way to get lazy behavior would be to insert toStream: "(1 to 20).toStream.takeWhile". in general, though, mixing for comprehensions and side-effects is discouraged. つまり下記のように(1 to 20)の部分を(1 to 20).toStreamとすればよいようです。 var continue = true for (x <- (1 to 20).toStream.takeWhile(e => continue)) { println(x) continue = x < 5 } **配列の連結 [#lb9151aa] 配列の連結は先頭にしかできないので どうしても末尾にしたい場合は、 reverseをつかって先頭に追加してから、 またreverseでもどしたりする。 **文字列格納用配列の宣言 [#m0b9dc5b] var result :List[String] = List() が正解で var result = List() ......NG Error だと、空配列しか受け付けない配列として宣言したことになるようです。 ***配列の追加 [#of21c1dc] 配列が先頭にしか追加できない result = "a" :: result だとエラーにならないけど result = result :: "a" だとエラーになるってこと ***戻り値のあるメソッドの書き方注意点 [#mc57b072] メソッドの戻り値がある場合は、メソッドの中身を書く際に={中身}とすること そうしないと illegal start of declaration というエラーがかえってきます。 ***キャストの仕方 [#h4071f02] クラスの型を正しく指定しないといけませんので指定します。 BufferedSourceでキャストする方法 .asInstanceOf[BufferedSource]. ***動的変数を持つ関数の作り方 [#a10ec873] 動的変数は try catch の中のプログラムをブロックとして、 あとで追加できるようにする仕組みで、ファイルを閉じるなどの 必ず行うような処理を簡潔に書くことができます。 def 動的関数名(引数)(動的変数 => Unit){ } ***動的変数を持つ関数の使い方 [#ib5c9174] 動的関数名(引数){(動的変数 ) => 処理内容 } **文字列を配列に変換する [#nc5cd2c6] ファイルから読み込んだ文字列の場合、いったん配列にしてやらないといけない だから文字列を配列に変換するメソッドをつくってみました。 def to_a(text:String):List[String] ={ var result :List[String] = List() var len = text.length; for (x <- (0 to text.length -1)){ result = text.substring(len-x-1,len-x) :: result } result } 別解:JavaのtoCharArrayをつかう例。これだけでもいいけどArray型になってしまうため、型変換メソッドも用意しました。 //ArrayをList配列に変換します。 def toListoReverse(array:Array[Char]):List[Char]={ var result :List[Char] = List() array.foreach{ x=>result = x :: result } result } //文字列を配列に変換します。 def toList(string:String):List[Char]={ toListoReverse(string.toCharArray).reverse } **ファイルの読み込みを動的変数で簡潔にする [#s98a5e3d] ファイルの読み込みはclose処理をいれなきゃいけないのですが、 動的関数をつかえば、簡潔に表現できます。 import scala.io.Source import scala.io.BufferedSource import java.io._ // ファイルの読み込みを動的変数で簡潔にする def read(path: String)(block: Source => Unit) ={ var fis :FileInputStream =null var sou :Source =null try { fis= new FileInputStream(path) sou= Source.fromInputStream(fis) block(sou) }finally{ sou.asInstanceOf[BufferedSource].close fis.close } } //readメソッドの使い方はこんな感じ read("sample.txt"){(in:Source) => for(line <- in.getLines){ println(line.stripLineEnd) } } ファイルをcloseする箇所が省けているのがわかります。 ***応用:ファイルの内容を一気に配列化するメソッド [#re0a257f] //ファイルをすべて読み配列で返します。 def readAll(path: String):List[String]={ var result :List[String] = List() read(path){(in:Source) => for(line <- in.getLines){ result = line.stripLineEnd :: result } } result.reverse } //使い方 readAll("sample.txt").foreach(println _) とってもシンプルになりました。 *問07 [#u51f94f7] **scala.Anyとは [#sea29c93] Scala のすべてのクラスの継承元となる基底クラス (Int、Float、Double などの型やその他の数値型) は scala.Any 型です。 **入れ子状態になっている配列の入れ子を解消してフラットな配列にする [#pfa20fee] flatMapをつかいます。flatMapは基礎的メソッドです。 def flatten(l: List[Any]): List[Any] = l flatMap { case l: List[_] => flatten(l) case e => List(e) } -flatmapもmapもArray()で行えば、Arrayをかえしますし、Listで行えばListをかえします。 - => 記号は左側にブロック変数を指定できるので重要です。 - さらにブロック変数はcaseによってリストのパターンごとの処理が可能になっています。 *問08 [#e36ac1fa] **値が一致する要素を削除する [#v5207dcb] match処理内のcase処理部分でつかいます。 tail.dropWhile(_ == e) 普通に式を評価しようとするとvalue dropwhile is not a member of Listとエラーになります。 *問09 [#m0f568a4] Haskellでいうところのgroupメソッドとかなり類似した関数のようですね。 最近、下記のようなところでもりあがっているのを知りました。 http://wordprogress.org/archives/366 それはさておき、ここの回答でつかわれているテクニックに焦点をあててみていきましょう。 **多重代入 [#r04dde2d] ScalaもRubyのように多重代入ができるんですねぇ。 scala> val (aa,bb)=(11,22) aa: Int = 11 bb: Int = 22 ***List形式の場合の多重代入 [#tfc30d30] scala> var list = List(1,2,3) list: List[Int] = List(1, 2, 3) scala> var List(aa,bb,cc)=list aa: Int = 1 bb: Int = 2 cc: Int = 3 ***一致するシンボルと、それ以降を分離する。span [#b07ff58f] spanをつかいます。 -例 l.span(_ == l.head) scala> var l = List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e) scala> l.span(_ == l.head) res16: (List[Symbol], List[Symbol]) = (List('a, 'a, 'a, 'a),List('b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)) *問10 [#d9f67211] えーっとここの問10の記事でバッチファイル作りなど、いろいろ脱線した記事を書いているので、無視してもらっていいです。 前回で定義したメソッドと連携して最小限のメソッド実装で問題を解いていきます そのためには前回定義したメソッドをimportします。 import P09.pack インポートするためには参照元の.scalaファイルがコンパイルされている必要があります。 さもなくば、下記のエラーが出ます。 P09 is not a member of problem というわけで、 scalac P09.scala でコンパイルすればいいんですが、 今後プロジェクトでこの99の問題をコンパイルし続けるとディレクトリ内はソースとクラスファイルでごちゃごちゃになってしまいます。 それを防ぐためには、ソースファイルとクラスファイルの出力先を分けたたほうがいいですし、 そして問題の回答としてできてくる99個のファイルは一つのパッケージにしなきゃつらいですね。 となると、package化の必要があります。と、なると -フォルダ構成は プロジェクト名 +---src +---problem <---パッケージ名 +---target +classes <----出力フォルダ で、いちいちscalacのオプションを書くのは面倒なのでバッチファイルをつくりました。 拡張子の.scalaは省略してもいいようにしてあります。 --ただし、jarファイルのクラスパスをまとめてコンパイルするにはさらなるクラスパスの追加が必要です。 **バッチファイルでの特定の拡張だけのパスを集める最小限的のサンプル [#r054caaa] @echo off set CP=. set BASE=. setlocal ENABLEDELAYEDEXPANSION for %%f in (%BASE%\*.jar) do set CP=!CP!;%%f echo %CP% ---setlocalはこのバッチファイルだけで有効なことを意味します。 ---ENABLEDELAYEDEXPANSIONを指定しないと、for文が並列で評価されてしまい、クラスパスが連結されません。 ---forには /R というサブディレクトリも検索対象にするオプションがあるはずですが、なぜか自分の環境(XP)では動作しませんでした。 **クラスパスの指定に偽ワイルドカード [#z3e0e43b] Java SE 6 では、クラスパスの指定に偽ワイルドカードが使えるようになるようです。 なんで偽かっていうと ---java -cp ./*.jar;./lib/*.jar のように *.jar とか書くとダメ ---java -cp ./*;./lib/* のみ対応 設定箇所はプロジェクトのディレクトリです。 -compile.bat REM プロジェクトのディレクトリを設定 SET PROJECT=C:\scala\problem SET SRC=%PROJECT%\src SET CLASS=%PROJECT%\bin scalac -sourcepath %SRC% -classpath %CLASS% -d %CLASS% %SRC%\%1.scala -実行方法 compile.bat problem\P09 **ビルドツールの出番 [#j9107d6c] でもimportするということは、ファイル同士に依存関係が出てくるということです。 ということは、 いまは例題を1から順番にやっているだけなので順番にコンパイルしていけばいいのですが、 業務でつかうとなれば、ビルドツールのANTまたは、MAVENをつかったほうがよさそうです。 **ビルドツールMAVEN [#p35eafcc] ダウンロード http://maven.apache.org/download.html 仮に解凍したディレクトリの名称をmavenに変更して下記に設置したとします。 C:\maven -環境変数を設定します。 -M2_HOME=C:\maven -M2=%M2_HOME%\bin -PATH=%PATH%;%M2% -mavenの環境変数設定の確認 mvn --version -mvnでscalaをつかうためのおまじない --参考 ---http://codezine.jp/article/detail/4476?p=2 ---http://akisute.com/2009/11/maven2scalahello-world.html 参考サイトによればできたプロジェクトにpom.xmlがありますが、プラグインのバージョンを合わせるためこれを修正しなくてはなりませんが、 お決まりの操作なので バッチファイルとrubyでつくったスクリプトを用意しました。 なんで、rubyかって?単に簡潔に書けそうな気がしたからです。 --プロジェクト作成バッチファイル **mkprj.bat [#wec0a917] SET PROJECT=%1 SET PACKAGE=%2 SET RUBYSCRIPT=c:\scala\bin\scalaproject.rb @echo off if exist %PROJECT% GOTO PROCESS1 SET CREATE=org.apache.maven.plugins:maven-archetype-plugin:1.0-alpha-7:create SET PARAM= -DarchetypeGroupId=org.scala-tools.archetypes SET PARAM=%PARAM% -DarchetypeArtifactId=scala-archetype-simple SET PARAM=%PARAM% -DarchetypeVersion=1.2 SET PARAM=%PARAM% -DremoteRepositories=http://scala-tools.org/repo-releases mvn %CREATE% %PARAM% -DgroupId=%PACKAGE% -DartifactId=%PROJECT% :PROCESS1 if exist %PROJECT%\pom.xml.bat GOTO PROCESS2 ruby %RUBYSCRIPT% c:\scala\bin\scalaproject.rb %PROJECT% %PACKAGE% %3 :PROCESS2 --使い方 ---したに示したテキストファイル処理Rubyスクリプトがあることが前提のバッチファイルです。 ---プロジェクトフォルダがないことが前提です。 cd プロジェクトの親ディレクトリ mkprj プロジェクト名 パッケージ名 合わせたいscalaバージョン --例 mkprj problem99 problem 2.7.7 **scalaproject.rb [#qfa58e1d] #プロジェクト名を第一引数にとります。 #パッケージ名を第2引数にとります。 #バージョンを第3引数にとります。 puts "argv[0]:"+ARGV[1] projectname =ARGV[1] filename = projectname + "\\pom.xml" file = open(filename) # 保存用バッファ buffer = file.read().split("\n"); file.close # バックアップ用ファイルを開く bkup = File.open(filename + ".bak" , "w"); # ファイルから読み込んでバックアップに書き込む bkup.write(buffer); bkup.close # ファイルを書き込みモードで開き直す file = File.open(filename , "w"); #処理 cnt = 0 buffer.each {|line| cnt = cnt + 1 #64行目から66行目をカットします。 if !(64..66).include?(cnt) #以前のバージョン2.7.0を今のバージョンに置き換えます。 file.puts line.gsub("2\.7\.0",ARGV[3]) #初期値では if cnt==94 heredoc= <<EOS <!-- このlaunchers要素を新規に作る。idとmainClassは必須。 --> <launchers> <launcher> <id>app</id> <mainClass>PACKAGE.App</mainClass> <!-- 以下、任意要素。 args と jvmArgs を指定できます。 --> <!-- <args> <arg>arg1</arg> </args> <jvmArgs> <jvmArg>-Xmx128m</jvmArg> <jvmArg>-Djava.library.path=...</jvmArg> </jvmArgs> --> </launcher> </launchers> EOS file.puts heredoc.gsub("PACKAGE",ARGV[2]) end end } file.close **実行 [#c825ff25] mkprj.bat problem99 problem 2.7.7 はなぜかコンパイルし終わると停止するので2度実行しています。 mkprj.bat problem99 problem 2.7.7 mkprj.bat problem99 problem 2.7.7 cd problem99 mvn scala:run **問09をMavenで実行させてみる。 [#i8df2544] -P09.scala package problem object P09 { def pack[T](l: List[T]): List[List[T]] = { if (l.isEmpty) List(List()) else { val (packed, next) = l.span(_ == l.head) if (next == Nil) List(packed) else packed :: pack(next) } } } -P10.scala package problem object P10 { import problem.P09.pack def encode[T](l: List[T]): List[(Int, T)] = pack(l).map(e => (e.length, e.head)) } -App.scala 改 package problem /** * Hello world! * */ object App extends Application { println( "Hello World!" ) import problem.P10._ println(encode(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e))) } **実行 [#tf761882] mvn scala:run とりあえず、ソースをかけば、コンパイルから実行までやってくれるのがわかった。 さすがに、scalecを直接やるよりは遅い ***クラスファイルの出力先 [#t56c78be] プロジェクトフォルダ\target\classes ***インタプリタ形式でscalaを動かしたい場合 [#eccca17d] cd プロジェクトフォルダ\target\classes scala *問11 [#y2180116] **単純な括弧、たとえば、(1,2)の要素を取得する [#nb895eea] 今まで、List型の要素取得方法を学んだ scala> List(1,2)(1) res12: Int = 2 しかし、同様の操作を上記のListを省いた形式にあてはめようとするとえらーになる。 scala> (1,2)(1) <console>:7: error: scala.Tuple2.apply[Int, Int](1, 2) of type (Int, Int) does not take parameters ***単なる括弧の要素を取得する方法 [#p3f396f6] scala> (1,2)._1 res11: Int = 1 --この単なる括弧の正体はscala.Tuple2である。 scala> scala.Tuple2.apply[Int, Int](1, 2) == (1,2) res16: Boolean = true 引数の型の数だけTupleクラスが用意されていて、APIを見る限り22個までは用意してあるらしい -22個の例 scala> (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22) res22: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22) 正常に解釈される -23個の例 scala> (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23) <console>:7: error: value Tuple23 is not a member of package scala (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23) 宣言されていないのでエラーとなった。 *問12 [#vba60999] **List.make(2,'a)はList('a,'a) [#v18c1998] **これまでの問題で定義してきたメソッドをあたかもListのビルトインメソッドのように扱う [#bbf78db3] 問題文では、decode(List( (4, 'a), (1, 'b), (2, 'c), (2, 'a), (1, 'd), (4, 'e))) であったが、これを -List((4, 'a), (1, 'b), (2, 'c), (2, 'a), (1, 'd), (4, 'e)).decode で答えが出るようにするには、 case class P12[T](val nums : List[(Int, T)]){ def decode:List[T] = nums.flatMap(e => List.make(e._1, e._2)) } implicit def xxx[T]( num:List[(Int, T)]) = P12(num) -対比のため掲載するが、もとの回答ではつぎのようになる object P12 { def decode[T](l: List[(Int, T)]): List[T] = l.flatMap(e => List.make(e._1, e._2)) } -ポイント --case classでは classで引数をとるようになっており、defの引数が一つ減っている。 *問13 [#jdfa5258] **spanの結果を多重代入する [#y5b22cf6] val (packed, next) = l.span(_ == l.head) *問14 [#t5c21c38] **flatMapを使った方法を思いつくかという問題 [#p995fdd9] #areaedit *問15 [#v7bc29a2] **List.make(n, _)をつかって要素を増やした記述 [#q74067a4] def drop[T](n: Int, l: List[T]): List[T] = { def dropR(c: Int, curList: List[T]): List[T] = (c, curList) match { case (_, Nil) => Nil case (1, _ :: tail) => dropR(n, tail) case (_, e :: tail) => e :: dropR(c - 1, tail) } dropR(n, l) } 回答をみて気がつくのは、defの定義方法である。通常{}でくくるかとおもうが、 いきなり( )表現をつかっている。一つの配列からつくられる高階関数内に処理を書けるからだとおもう。 case文の使い方で気がつくことは、eとtailである、この2つは、どこにも定義や代入の記述がないことをみると、予約されている変数だろう。パターンマッチの書き方も()に応じて用意してあるのだろう。たしか()はTuple2だったはずだ。 #areaedit(end) #areaedit *問16 [#mf5b3ecb] **この問題の回答例1番目で学べるのはカウンターを使って周期的にcase文を選択させていることが学べます。 [#w54f70f2] **zipWithIndex [#v99716b0] Rubyでのeach_with_indexみたいにインデックス番号付きに変換します。 ***例文 [#wd42b26d] List(2, 3, 5).zipWithIndex.foreach(t => println(t._2 + ":" + t._1)) for ((d, i) <- List(2, 5, 6).zipWithIndex) {println(i + ":" + d)} List(7, 3, 1).zipWithIndex.foreach{case (d, i) => println(i + ":" + d)} **filter [#ee114a99] 条件式に一致する要素を抽出します。 def drop[T](n: Int, l: List[T]): List[T] = l.zipWithIndex.filter(v => (v._2 + 1) % n != 0).map(_._1) } #areaedit(end) *問17 [#g18f5769] **splitAtというビルトインメソッドで分割する例 [#p6015899] -例 def split[T](n: Int, l: List[T]): (List[T], List[T]) = l.splitAt(3) -例 takeとdropをつかって先頭と末尾を分割し取得する例 def split[T](n: Int, l: List[T]): (List[T], List[T]) = (l.take(n), l.drop(n)) #areaedit *問18 [#bfd8a868] slice関数を使った回答が一番簡単な問題です。 def slice[T](start: Int, end: Int, l: List[T]): List[T] = l.slice(start, end) #areaedit(end) #areaedit *問19 [#k6bcc473] dropとtakeを使って:::で連結することで、rotateを実現しています。 #areaedit(end) #areaedit *問20 [#t3f24544] 問17でも使った、spiltAtとmatchを使って解くと解ける問題 #areaedit(end) #areaedit *問21 [#t3f24544] これも問17でも使った、spiltAtとmatchを使って解くと解ける問題 spiltAtを使ってからmatchを使うとpreとpostに分割されている。 そこで、 case (pre, post) => と、書きます。 #areaedit(end) *問22 [#v30bba7a] #areaedit 組み込みの変数にRangeが用意されていますが、第二引数未満の整数のリストを作成するようです。 def range(start: Int, end: Int): List[Int] = List.range(start, end + 1) #areaedit(end) *問23 [#lae006e4] #areaedit 乱数の使い方を知っていると解ける (new util.Random).nextInt(l.length) #areaedit(end) *問24 [#mfb2e24e] #areaedit 配列を生成するには下記のようにRangeを使うとよい List.range(1, max + 1) #areaedit(end) *問25 [#s702653f] #areaedit mutable array のupdateを使う #areaedit(end) *問26 [#yfe9b244] #areaedit sublist@を使う // P26 (**) Generate the combinations of K distinct objects chosen from the N // elements of a list. // In how many ways can a committee of 3 be chosen from a group of 12 // people? We all know that there are C(12,3) = 220 possibilities (C(N,K) // denotes the well-known binomial coefficient). For pure mathematicians, // this result may be great. But we want to really generate all the possibilities. // // Example: // scala> combinations(3, List('a, 'b, 'c, 'd, 'e, 'f)) // res0: List[List[Symbol]] = List(List('a, 'b, 'c), List('a, 'b, 'd), List('a, 'b, 'e), ... object P26 { def combinations[T](n: Int, l: List[T]): List[List[T]] = { // flatMapSublists is like list.flatMap, but instead of passing each element // to the function, it passes successive sublists of L. def flatMapSublists[U](l: List[T], f: (List[T]) => List[U]): List[U] = l match { case Nil => Nil case sublist@(_ :: tail) => f(sublist) ::: flatMapSublists(tail, f) } if (n == 0) List(Nil) else flatMapSublists(l, (sl) => combinations(n - 1, sl.tail).map((c) => sl.head :: c)) } } **難しい記述 [#p0dc7cf4] -def flatMapSublists[U](l: List[T], f: (List[T]) => List[U]): List[U] の[U]の書き方 -sublist@の書き方 -slの定義について #areaedit(end) *問27 [#f0a6d1f6] #areaedit すでに問題26で得ている解法というか、メソッドを使えば、この問題27を単純化できることに気がつく object P27 { import P26.combinations def group3[T](l: List[T]): List[List[List[T]]] = for { a <- combinations(2, l) noA = l -- a b <- combinations(3, noA) } yield List(a, b, noA -- b) def group[T](ns: List[Int], l: List[T]): List[List[List[T]]] = ns match { case Nil => List(Nil) case n :: ns => combinations(n, l).flatMap(c => group(ns, l -- c).map(rest => c :: rest)) } } **配列の組み合わせによるfor文 [#m087461b] scalaではfor文は配列の要素をループのカウントがわりに用いることができる。 **yield文 [#zca5424d] for文のあとに記述することで、 for文のループ中の要素をyield文中のプログラムを実行することが可能です。 ** --表記 [#d0d5cd6c] noA = l -- a 配列lから、配列aの要素を除いたモノを返す #areaedit(end) *問28 [#pb5e47d7] #areaedit slacaの配列のソートはsortメソッドが用意されています。 このsortメソッドに比較コードを書くことでsortが実施されます。 比較コードには、scala独特の _ で比較対象の要素を示すことが可能です。 問題bの方は、既に問題10で作成した、要素の長さの配列を得るメソッドを活用します。 既に作った関数をうまく使うことができるかどうかという問題でもあるわけですね。 #areaedit(end) *問29 [#va10fb0e] 素数を扱う問題で 7.isPrime と記述できるなんて、数値がオブジェクトでありなおかつ、そのメソッドを定義できるということですよね。 Scala言語がいかに洗練された言語かがわかります。 class S99Int(val start: Int) { def isPrime = primes.takeWhile(_ <= Math.sqrt(start)).forall(start % _ != 0) } object S99Int { def primes: Stream[Int] = Stream.cons(2, Stream.from(3, 2).filter(_.isPrime)) } 上記のコードを2.8.0 RC3で実行してみたところエラーが出ました。 <console>:7: error: not found: value primes (start > 1) && (primes takeWhile { _ <= Math.sqrt(start) } forall { start % _ != 0 }) となってしまいました。
テキスト整形のルールを表示する