5

それぞれが一連のタスクを含むジョブで構成されたデータ構造があります。Job と Task の両方のデータは、次のようなファイルで定義されます。

jobs.txt:
JA
JB
JC

tasks.txt:
JB  T2
JA  T1
JC  T1
JA  T3
JA  T2
JB  T1 

オブジェクトを作成するプロセスは次のとおりです。
- 各ジョブを読み取り、ID で作成して保存し
ます - タスクを読み取り、ID でジョブを取得し、タスクを作成し、タスクをジョブに保存します

ファイルが読み込まれると、このデータ構造は決して変更されません。したがって、ジョブ内のタスクが不変セットに格納されることを望みます。しかし、効率的な方法でそれを行う方法がわかりません。(注: ジョブを格納する不変のマップは、不変のままにすることができます)

コードの簡略版は次のとおりです。

class Task(val id: String) 

class Job(val id: String) {
    val tasks = collection.mutable.Set[Task]() // This sholud be immutable
}

val jobs = collection.mutable.Map[String, Job]() // This is ok to be mutable

// read jobs
for (line <- io.Source.fromFile("jobs.txt").getLines) { 
    val job = new Job(line.trim)
    jobs += (job.id -> job)
}

// read tasks
for (line <- io.Source.fromFile("tasks.txt").getLines) {
    val tokens = line.split("\t")
    val job = jobs(tokens(0).trim)
    val task = new Task(job.id + "." + tokens(1).trim)
    job.tasks += task
}

いつもご提案ありがとうございます。

4

4 に答える 4

4

これを行う最も効率的な方法は、すべてを可変構造に読み取り、最後に不変構造に変換することですが、これには、多くのフィールドを持つクラスに対して多くの冗長コーディングが必要になる場合があります。したがって、代わりに、基になるコレクションが使用するのと同じパターンを使用することを検討してください。新しいタスクを持つジョブは新しいジョブです。

これは、ジョブリストを読むことすら気にしない例です。タスクリストから推測します。(これは2.7.xで動作する例です。2.8の最近のバージョンでは、「Source.fromFile」ではなく「Source.fromPath」が使用されています。)

object Example {
  class Task(val id: String) {
    override def toString = id
  }

  class Job(val id: String, val tasks: Set[Task]) {
    def this(id0: String, old: Option[Job], taskID: String) = {
      this(id0 , old.getOrElse(EmptyJob).tasks + new Task(taskID))
    }
    override def toString = id+" does "+tasks.toString
  }
  object EmptyJob extends Job("",Set.empty[Task]) { }

  def read(fname: String):Map[String,Job] = {
    val map = new scala.collection.mutable.HashMap[String,Job]()
    scala.io.Source.fromFile(fname).getLines.foreach(line => {
      line.split("\t") match {
        case Array(j,t) => {
          val jobID = j.trim
          val taskID = t.trim
          map += (jobID -> new Job(jobID,map.get(jobID),taskID))
        }
        case _ => /* Handle error? */
      }
    })
    new scala.collection.immutable.HashMap() ++ map
  }
}

scala> Example.read("tasks.txt")
res0: Map[String,Example.Job] = Map(JA -> JA does Set(T1, T3, T2), JB -> JB does Set(T2, T1), JC -> JC does Set(T1))

別のアプローチでは、ジョブリストを読み取り(ジョブをnew Job(jobID、Set.empty [Task])として作成)、タスクリストにジョブリストにないエントリが含まれている場合のエラー状態を処理します。(新しいタスクを読み込むたびに、ジョブリストマップを更新する必要があります。)

于 2010-02-08T19:36:23.027 に答える
2

Scala 2.8 で動作するようにフィールの変更を行いました (ほとんどの場合、 のfromPath代わりにfromFileとの()getLines)。いくつかの Scala 2.8 機能を使用している可能性がありますgroupBy。おそらくtoSet同様ですが、これは 2.7 に簡単に適応できます。

テストするためのファイルはありませんが、これを から に変更しましvaldef。少なくとも型シグネチャは一致しています。

class Task(val id: String)  
class Job(val id: String, val tasks: Set[Task])

// read tasks 
val tasks = (
  for {
    line <- io.Source.fromPath("tasks.txt").getLines().toStream
    tokens = line.split("\t") 
    jobId = tokens(0).trim
    task = new Task(jobId + "." + tokens(1).trim) 
  } yield jobId -> task
).groupBy(_._1).map { case (key, value) => key -> value.map(_._2).toSet }

// read jobs 
val jobs = Map() ++ (
  for {
    line <- io.Source.fromPath("jobs.txt").getLines()
    job = new Job(line.trim, tasks(line.trim))
  } yield job.id -> job
)
于 2010-02-08T20:03:01.507 に答える
1

次のように、ファイルからすべてのデータが読み込まれるまで、オブジェクトの作成をいつでも遅らせることができます。

case class Task(id: String) 
case class Job(id: String, tasks: Set[Task])

import scala.collection.mutable.{Map,ListBuffer}
val jobIds = Map[String, ListBuffer[String]]()

// read jobs
for (line <- io.Source.fromFile("jobs.txt").getLines) { 
    val job = line.trim
    jobIds += (job.id -> new ListBuffer[String]())
}

// read tasks
for (line <- io.Source.fromFile("tasks.txt").getLines) {
    val tokens = line.split("\t")
    val job = tokens(0).trim
    val task = job.id + "." + tokens(1).trim
    jobIds(job) += task
}

// create objects
val jobs = jobIds.map { j =>
    Job(j._1, Set() ++ j._2.map { Task(_) })
}

より多くのフィールドを処理するために、(ある程度の努力を払って)構築に使用される不変クラスの可変バージョンを作成できます。次に、必要に応じて変換します。

case class Task(id: String)
case class Job(val id: String, val tasks: Set[Task])
object Job {
    class MutableJob {
        var id: String = ""
        var tasks = collection.mutable.Set[Task]()
        def immutable = Job(id, Set() ++ tasks)
    }
    def mutable(id: String) = {
        val ret = new MutableJob
        ret.id = id
        ret
    }
}

val mutableJobs = collection.mutable.Map[String, Job.MutableJob]() 

// read jobs
for (line <- io.Source.fromFile("jobs.txt").getLines) { 
    val job = Job.mutable(line.trim)
    jobs += (job.id -> job)
}

// read tasks
for (line <- io.Source.fromFile("tasks.txt").getLines) {
    val tokens = line.split("\t")
    val job = jobs(tokens(0).trim)
    val task = Task(job.id + "." + tokens(1).trim)
    job.tasks += task
}

val jobs = for ((k,v) <- mutableJobs) yield (k, v.immutable)
于 2010-02-08T17:05:48.003 に答える
0

ここでの1つのオプションは、上記の行に沿って可変であるが一時的なconfigurerクラスを作成し、これを不変の形式で実際のクラスにMutableMap渡すことです。

val jobs: immutable.Map[String, Job] = {
  val mJobs = readMutableJobs
  immutable.Map(mJobs.toSeq: _*)
}

そしてもちろんreadMutableJobs、あなたはすでにコーディングした線に沿って実装することができます

于 2010-02-08T16:10:32.660 に答える