2013-04-25 96 views
12

我在这一块的墙上敲我的头。 (仅供参考,我不是一个阶亲,但我就喜欢大的时候)斯卡拉 - 在列表中找到一个特定的元组

比方说,我们有元组名单:

val data = List(('a', List(1, 0)), ('b', List(1, 1)), ('c', List(0))) 

名单有这样的签名:

List[(Char, List[Int])] 

我的任务是从“data”中的元组中获取“List [Int]”元素,该元素的关键字是,比如说,字母“b”。

换句话说,如果我实现像“findIntList(数据,‘B’)”的方法,那么我期待(1,1)

刚刚完成的图片,我已经尝试列出的结果以下方法。问题是,对于所有的方法(除了方法1,我使用明确的“返回”),我要么收到List[Option]List[Any]对象,我不知道如何从

中提取“ List[Int]”信息

方法1:

data.foreach { elem => if (elem._1 == char) return elem._2 } 

方法2:

data.find(x=> x._1 == ch) 

方法3:

for (elem <- data) yield elem match {case (x, y: List[Bit]) => if (x == char) y} 

方法4:

for (x <- data) yield if (x._1 == char) x._2 
+0

如果你有'Option(char,List [Bit])',比如你从'data.find'得到的东西,你可以用'.get'得到实际的元组:注意它会抛出如果没有发现任何异常。在这项任务中,我只写了自己的功能,因为高阶列表功能仅在第5周推出。 – 2013-04-25 04:44:17

+0

(https://www.coursera.org/course/progfun) – 2013-04-25 04:49:40

+0

感谢Mark! .get是这里的神奇 – mainas 2013-04-25 05:01:37

回答

17

一个的许多方式:

data.toMap.get('b').get 

toMap的2元组的列表从所述元组到所述第二的第一个元素转换成Mapget为您提供给定密钥的值并返回Option,因此您需要另一个get才能真正获得该列表。

或者你可以使用:

data.find(_._1 == 'b').get._2 

注意:仅使用得到Option时,你可以保证你将有一个Some而不是None。有关如何使用Option惯用语的信息,请参阅http://www.scala-lang.org/api/current/index.html#scala.Option

更新:你与你的不同看到的结果类型的说明方法

方法2:找到返回一个选项[列表[INT]],因为它不能保证一个匹配的元素被发现。

方法3:这里您基本上做了一个map,即您将一个函数应用于您的集合中的每个元素。对于您正在查找的元素,函数返回所有其他元素的List [Int],它包含的值为(),这是Unit的值,大致相当于Java中的void,但是实际类型。由于'List [Int]'和'Unit'唯一常见的超类型是'Any',所以你会得到'List [Any]'作为结果。

方法4是基本相同#3

+0

当一个NoSuchElementException异常抛出是否是正确的异常时,对未知选项使用'get'可以接受吗? – 2013-04-25 04:47:21

+1

@MarkPeters我会考虑抛出异常不好的风格(当然不是惯用的)。所以我猜如果你实现了一些支持这种行为的API,并且你不能改变它就没问题。否则,请更改API以返回选项或Try(http://www.scala-lang.org/archives/downloads/distrib/files/nightly/docs/library/index.html#scala.util.Try)或如果你喜欢Scalaz a Validation(http://blog.lunatech.com/2012/03/02/validation-scala) – 2013-04-25 04:56:19

+0

data.find(_._ 1 =='b')。get._2 ----- - 我爱天才!谢谢Jens。它的工作 – mainas 2013-04-25 05:02:27

1

另一种方式是

data.toMap.apply('b') 

或被一个中间步骤,这甚至更好:

val m = data.toMap 
m('b') 

其中apply使用含蓄地说,即最后一行相当于

m.apply('b') 
+0

为什么data.toMap('b')不起作用? – thetrystero 2016-08-07 03:44:18

+0

@thetrystero:我认为这是由于'toMap'有一个隐含的参数。 – chris 2016-08-08 10:42:53

0

有多种方式可以做到这一点。另一种方式:

scala> def listInt(ls:List[(Char, List[Int])],ch:Char) = ls filter (a => a._1 == ch) match { 
| case Nil => List[Int]() 
| case x ::xs => x._2 
| } 
listInt: (ls: List[(Char, List[Int])], ch: Char)List[Int] 
scala> listInt(data, 'b') 
res66: List[Int] = List(1, 1) 
0

你可以尝试像(当你确信它的存在),只需添加类型信息。

val char = 'b' 
data.collect{case (x,y:List[Int]) if x == char => y}.head 

或使用headOption如果你不知道的字符存在

data.collect{case (x,y:List[Int]) if x == char => y}.headOption 
0

您也可以解决这个使用模式匹配。请记住,您需要使其递归。解决方案应该看起来像这样;

def findTupleValue(tupleList: List[(Char, List[Int])], char: Char): List[Int] = tupleList match { 
    case (k, list) :: _ if char == k => list 
    case _ :: theRest => findTupleValue(theRest, char) 
} 

这将做什么是递归地走你的元组列表。检查头元素是否符合您的条件(您正在查找的键),然后将其返回。或继续完成列表的其余部分。