11

Scalaではリストは不変なので、その要素を「削除」する方法、つまり実際には新しいコレクションを作成する方法を見つけて、リストに作成されたギャップを埋めようとしています。これは、マップを使用するのに最適な場所のように思えますが、この場合の開始方法がわかりません。

コースは文字列のリストです。このループが必要なのは、実際にはそのインデックスの要素を削除する必要があるリストがいくつかあるためです(複数のリストを使用して、リスト全体に関連付けられたデータを格納しています。これは、インデックスが常に常に行われるようにすることで実行しています。リスト間で対応)。

  for (i <- 0 until courses.length){
    if (input == courses(i) {
    //I need a map call on each list here to remove that element
    //this element is not guaranteed to be at the front or the end of the list
    }
  }
}

問題にいくつかの詳細を追加しましょう。インデックスによって相互に関連付けられている4つのリストがあります。1つのリストにはコース名が格納され、1つはクラスの開始時刻が単純なint形式(つまり130)で格納され、1つは「am」または「pm」のいずれかが格納され、もう1つはクラスの日数がint(つまり「MWF」)で格納されます。 1への評価、「TR」は2への評価など)。これが複数あることがこの問題を解決するための最良の方法なのか「正しい」方法なのかはわかりませんが、これらはすべて私が持っているツールです(16歳のときから真剣にプログラムしていない1年生の計算機科学の学生)。各リストから対応する要素を削除する関数を作成しています。私が知っているのは、1)インデックスが対応し、2)ユーザーがコース名を入力することだけです。filterNotを使用して各リストから対応する要素を削除するにはどうすればよいですか?私はしません

4

6 に答える 6

13

これは次のユースケースですfilter

scala> List(1,2,3,4,5)
res0: List[Int] = List(1, 2, 3, 4, 5)

scala> res0.filter(_ != 2)
res1: List[Int] = List(1, 3, 4, 5)

リストのすべての要素を変換するときにマップを使用する必要があります。

于 2012-10-12T18:10:52.620 に答える
13

あなたの質問に直接答えるために、私はあなたが探していると思いますpatch、例えば、インデックス2( "c")を持つ要素を削除します:

List("a","b","c","d").patch(2, Nil, 1)      // List(a, b, d)

置換する文字はどこNilで、置換する1文字数はです。

しかし、これを行う場合:

インデックスによって相互に関連付けられている4つのリストがあります。1つのリストにはコース名が格納され、1つはクラスの開始時刻が単純なint形式(つまり130)で格納され、1つは「am」または「pm」のいずれかが格納され、もう1つはクラスの日数がintで格納されます。

あなたは悪い時間を過ごすつもりです。私はあなたが使用することをお勧めしますcase class

case class Course(name: String, time: Int, ampm: String, day: Int)

次に、それらをに保存しますSet[Course]。(時間と日をsとして保存Intすることも、良い考えではありませんjava.util.Calendar。代わりに見てください。)

于 2012-10-12T20:20:45.697 に答える
3

最初のいくつかの補足:

  1. Listインデックスベースの構造ではありません。その上でのすべてのインデックス指向の操作には線形時間がかかります。インデックス指向のアルゴリズムVectorの場合、はるかに優れた候補です。実際、アルゴリズムにインデックスが必要な場合は、Scalaの機能を実際に公開していないことを示しています。

  2. map単一の「A」から単一の「B」に渡されたトランスフォーマー関数を使用して、アイテム「A」のコレクションをアイテム「B」の同じコレクションに変換するのに役立ちます。結果の要素の数を変更することはできません。おそらくあなたはまたはと混同mapしていfoldますreduce

更新された質問に答えるには

さて、これがリストで効果的に機能する機能的なソリューションです:

val (resultCourses, resultTimeList, resultAmOrPmList, resultDateList)
  = (courses, timeList, amOrPmList, dateList)
      .zipped
      .filterNot(_._1 == input)
      .unzip4

しかし、落とし穴があります。このソリューションで使用されている関数型言語の基本的な関数が、標準のScalaライブラリに存在しないことに実際に驚いた。Scalaには、2項および3項のタプル用にそれらがありますが、他のタプルにはありません。

これを解決するには、次の暗黙の拡張機能をインポートする必要があります。

implicit class Tuple4Zipped 
  [ A, B, C, D ] 
  ( val t : (Iterable[A], Iterable[B], Iterable[C], Iterable[D]) ) 
  extends AnyVal 
  {
    def zipped 
      = t._1.toStream
          .zip(t._2).zip(t._3).zip(t._4)
          .map{ case (((a, b), c), d) => (a, b, c, d) }
  }

implicit class IterableUnzip4
  [ A, B, C, D ]
  ( val ts : Iterable[(A, B, C, D)] )
  extends AnyVal
  {
    def unzip4
      = ts.foldRight((List[A](), List[B](), List[C](), List[D]()))(
          (a, z) => (a._1 +: z._1, a._2 +: z._2, a._3 +: z._3, a._4 +: z._4)
        )
  }

この実装には、Scala 2.10が必要です。これは、既存のタイプをポン引きするための新しい効果的な値クラス機能を利用するためです。

私は実際に、ステートメントを追加するだけでそれらを使用できるプロジェクトに依存した後、SExtと呼ばれる小さな拡張機能ライブラリにこれらを含めました。import sext._

もちろん、必要に応じて、これらの関数を直接ソリューションに組み込むことができます。

val (resultCourses, resultTimeList, resultAmOrPmList, resultDateList)
  = courses.toStream
      .zip(timeList).zip(amOrPmList).zip(dateList)
      .map{ case (((a, b), c), d) => (a, b, c, d) }
      .filterNot(_._1 == input)
      .foldRight((List[A](), List[B](), List[C](), List[D]()))(
        (a, z) => (a._1 +: z._1, a._2 +: z._2, a._3 +: z._3, a._4 +: z._4)
      )
于 2012-10-12T18:17:27.703 に答える
2

リスト要素の削除とフィルタリング

Scalaでは、リストをフィルタリングして要素を削除できます。

scala> val courses = List("Artificial Intelligence", "Programming Languages", "Compilers", "Networks", "Databases")
courses: List[java.lang.String] = List(Artificial Intelligence, Programming Languages, Compilers, Networks, Databases)

いくつかのクラスを削除しましょう:

courses.filterNot(p => p == "Compilers" || p == "Databases")

removeを使用することもできますが、filterまたはfilterNotを優先して非推奨になりました。

インデックスで削除する場合は、を使用してリスト内の各要素を順序付きインデックスに関連付けることができますzipWithIndex。したがって、次のようにcourses.zipWithIndexなります。

List[(java.lang.String, Int)] = List((Artificial Intelligence,0), (Programming Languages,1), (Compilers,2), (Networks,3), (Databases,4))

courses.filterNot(_._2 == 1)これから2番目の要素を削除するには、リストを提供するタプルのインデックスを参照できます。

res8: List[(java.lang.String, Int)] = List((Artificial Intelligence,0), (Compilers,2), (Networks,3), (Databases,4))

最後に、別のツールを使用indexWhereして、任意の要素のインデックスを検索します。

courses.indexWhere(_ contains "Languages") res9: Int = 1

アップデートをやり直してください

各リストから対応する要素を削除する関数を作成しています。私が知っているのは、1)インデックスが対応し、2)ユーザーがコース名を入力することだけです。filterNotを使用して各リストから対応する要素を削除するにはどうすればよいですか?

Nikitaのアップデートと同様に、各リストの要素を「マージ」する必要があります。したがって、関連する要素を保持するには、コース、メリット、日、および時間をタプルまたはクラスに入れる必要があります。次に、タプルの要素またはクラスのフィールドでフィルタリングできます。

対応する要素をタプルに結合すると、このサンプルデータでは次のようになります。

val courses = List(Artificial Intelligence, Programming Languages, Compilers, Networks, Databases)
val meridiems = List(am, pm, am, pm, am)
val times = List(100, 1200, 0100, 0900, 0800)
val days = List(MWF, TTH, MW, MWF, MTWTHF)

それらをzipと組み合わせる:

courses zip days zip times zip meridiems

val zipped = List[(((java.lang.String, java.lang.String), java.lang.String), java.lang.String)] = List((((Artificial Intelligence,MWF),100),am), (((Programming Languages,TTH),1200),pm), (((Compilers,MW),0100),am), (((Networks,MWF),0900),pm), (((Databases,MTWTHF),0800),am))

この忌まわしさは、ネストされたタプルをタプルに平坦化します。より良い方法があります。

zipped.map(x => (x._1._1._1, x._1._1._2, x._1._2, x._2)).toList

作業するタプルの素晴らしいリスト。

List[(java.lang.String, java.lang.String, java.lang.String, java.lang.String)] = List((Artificial Intelligence,MWF,100,am), (Programming Languages,TTH,1200,pm), (Compilers,MW,0100,am), (Networks,MWF,0900,pm), (Databases,MTWTHF,0800,am))

最後に、を使用してコース名に基づいてフィルタリングできますfilterNot。例えばfilterNot(_._1 == "Networks")

List[(java.lang.String, java.lang.String, java.lang.String, java.lang.String)] = List((Artificial Intelligence,MWF,100,am), (Programming Languages,TTH,1200,pm), (Compilers,MW,0100,am), (Databases,MTWTHF,0800,am))

于 2012-10-12T18:11:09.477 に答える
0

私がこれからお答えするのは、これまでのコースで教えられたことを超えている可能性があるので、その場合はお詫び申し上げます。

まず、4つのリストが必要かどうかを疑問視するのは正しいことです。基本的に、必要なのはコースを表すオブジェクトのようです。

/**
 * Represents a course.
 * @param name the human-readable descriptor for the course
 * @param time the time of day as an integer equivalent to 
 *             12 hour time, i.e. 1130
 * @param meridiem the half of the day that the time corresponds 
 *                 to: either "am" or "pm"
 * @param days an encoding of the days of the week the classes runs.
 */
case class Course(name : String, timeOfDay : Int, meridiem : String, days : Int)

個別のコースを定義するために使用できます

val cs101 = 
  Course("CS101 - Introduction to Object-Functional Programming", 
         1000, "am", 1)

このタイプを定義するためのより良い方法があります(12時間の時間をより適切に表現する、曜日をより明確に表現するなど)が、元の問題ステートメントから逸脱することはありません。

これを考えると、コースの単一のリストがあります。

val courses = List(cs101, cs402, bio101, phil101)

また、特定の名前に一致するすべてのコースを検索して削除する場合は、次のように記述します。

val courseToRemove = "PHIL101 - Philosophy of Beard Ownership"
courses.filterNot(course => course.name == courseToRemove)

同様に、関数リテラルにScalaでアンダースコアシンタックスシュガーを使用します。

courses.filterNot(_.name == courseToRemove)

複数のコースが同じ名前である可能性があり(または正規表現またはプレフィックス一致を使用して一部の基準に基づいてフィルタリングしている)、最初の出現のみを削除したい場合は、次のように定義できます。それを行うための独自の関数:

def removeFirst(courses : List[Course], courseToRemove : String) : List[Course] =
  courses match {
    case Nil => Nil
    case head :: tail if head == courseToRemove => tail
    case head :: tail => head :: removeFirst(tail)
  }
于 2012-10-13T13:11:03.987 に答える
0

ListBufferを使用すると、Javaリストのような可変リストになります

 var l =  scala.collection.mutable.ListBuffer("a","b" ,"c")
 print(l) //ListBuffer(a, b, c)
 l.remove(0)
 print(l) //ListBuffer(b, c)
于 2013-05-22T14:35:05.533 に答える