列表在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
}
}
}
让我为问题添加一些细节。我有四个列表,通过索引相互关联;一个列表存储课程名称,一个存储类以简单的int格式开始的时间(即130),一个存储“am”或“pm”,一个存储类的日期(所以“MWF” evals to 1,“TR”evals to 2,等等。我不知道是否有多个这是解决这个问题的最佳或“正确”的方法,但这些都是我所拥有的工具(自从我16岁以来没有认真编程的第一年comp sci学生)。我正在编写一个函数来从每个列表中删除相应的元素,我所知道的是1)索引对应,2)用户输入课程名称。如何使用filterNot从每个列表中删除相应的元素?我不认为我对每个列表都有足够的了解,可以使用更高阶的函数。
答案 0 :(得分:12)
这是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)
您希望在转换列表的所有元素时使用map。
答案 1 :(得分:11)
要直接回答您的问题,我认为您正在寻找patch
,例如删除索引为2的元素(“c”):
List("a","b","c","d").patch(2, Nil, 1) // List(a, b, d)
其中Nil
是我们要替换的内容,1
是要替换的字符数。
但是,如果你这样做:
你将度过一段美好时光。我建议你使用我有四个按索引相互关联的列表;一 list存储课程名称,一个存储课程开始的时间 一个简单的int格式(即130),一个存储“am”或“pm”,以及一个 按int
存储类的日期
case class
:
case class Course(name: String, time: Int, ampm: String, day: Int)
然后将它们存储在Set[Course]
中。 (将时间和天数存储为Int
也不是一个好主意 - 请查看java.util.Calendar
。)
答案 2 :(得分:3)
List
不是基于索引的结构。所有面向索引的操作都需要线性时间。对于面向索引的算法,Vector
是一个更好的候选者。事实上,如果你的算法需要索引,那么你肯定不会暴露Scala的功能。
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)
)
答案 3 :(得分:1)
删除和过滤列表元素
在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")
你也可以使用删除但不推荐使用过滤器或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)
来引用元组中的索引,该列表给出了列表:
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))
答案 4 :(得分:0)
我即将给出的答案可能超越了你在课程中所教授的内容,所以如果是这种情况我会道歉。
首先,你有权质疑你是否应该有四个清单 - 从根本上说,它听起来像你需要的是一个代表一个过程的对象:
/**
* 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)
}
答案 5 :(得分: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)