列表在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",一个按int存储课程的天数(因此"MWF"evals为1,"TR"evals至2,等等)。我不知道拥有多个——这是解决这个问题的最好还是"正确"的方法,但这些都是我拥有的工具(一年级的compsci学生,从16岁起就没有认真编程)。我正在编写一个函数,从每个列表中删除相应的元素,我只知道1)索引对应,2)用户输入课程名称。如何使用filterNot从每个列表中删除相应的元素?我认为我对每个列表的了解不够,无法在它们上使用更高阶的函数。
这是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)
在转换列表的所有元素时,您希望使用贴图。
要直接回答您的问题,我认为您正在寻找patch
,例如删除索引为2("c")的元素:
List("a","b","c","d").patch(2, Nil, 1) // List(a, b, d)
其中Nil
是我们要替换它的内容,1
是要替换的字符数。
但是,如果你这样做:
我有四个列表,它们通过索引相互关联;一列表存储课程名称,其中一个存储开始上课的时间一个简单的int格式(即130),一个存储"am"或"pm",一个按int 存储类的天数
你会过得很糟糕。我建议你使用case class
:
case class Course(name: String, time: Int, ampm: String, day: Int)
然后将它们存储在CCD_ 6中。(将时间和天数存储为Int
s也不是一个好主意——请查看java.util.Calendar
。)
首先要注意几个方面:
-
List
不是一个基于索引的结构。对它的所有面向索引的操作都需要线性时间。对于面向索引的算法,CCD_ 10是更好的候选者。事实上,如果您的算法需要索引,那么这无疑表明您并没有公开Scala的功能。 -
CCD_ 11用于将项目集合";A";到相同的项目集合";B";使用来自单个"0"的传入变换器函数;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)
)
}
这个实现需要Scala2.10,因为它利用了新的有效的Value Classes特性来提升现有的类型。
实际上,我已经将它们包含在一个名为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)
)
删除和筛选列表元素
在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)
的元组中的索引,该索引给出了列表:
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))
我要给出的答案可能超出了你迄今为止在课程中所学的内容,所以如果是这样的话,我深表歉意。
首先,你质疑是否应该有四个列表是正确的——从根本上说,听起来你需要的是一个代表课程的对象:
/**
* 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)
}
使用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)