2013-04-17 33 views
14

有没有一种方式来指定一个模式匹配一​​个大小大于(或小于)或等于Scala中的某个值的列表?模式匹配的特定大小或更大/更小的列表

例如,如果我想同样的动作适用于大小为3或更低的全部名单:

list match { 
    case Nil => op(list) 
    case x :: Nil => op(list) 
    case x :: y :: Nil => op(list) 
    case x :: y :: z :: Nil => op(list) 
    case x :: tail => other(list) 
} 

有没有减少这两种情况下呢?

+0

我认为它可以用一个后卫来完成... ...的情况下,如果(tail.size> = X)=> – Dan

回答

11

是的,虽然你需要扭转的情况下,顺序:

list match { 
    case l @ (_ :: _ :: _ :: _) => other(l) 
    case l => op(l) 
} 

请注意,我已经绑定一个新的变量l在模式,而不是指list的列表,以及当我不需要变量时,我使用了_。我建议坚持这两种做法,但如果没有这些做法,答案将完全一样。

+1

我没有看到使用这种混淆的语法点时的保护条件这个工作是否在问题中提出。 –

+1

@ DenisR:首先,我回答了问题的提问,其次,我不确定这个答案实际上比守卫条件更不习惯,因为当你使用列表时,'长度'是一个昂贵的操作。如果你想避免遍历列表(你应该),你必须写'case l if l.lengthCompare(3)> -1',这是它自己的一种尴尬。 –

+1

你是对的复杂性和使用lengthCompare。 我更喜欢这个解决方案,因为长度是明确写入的,而不是写成一些“_”-1。 感谢您的解释。 –

6

简单的旧的if/else?有什么问题?

list.splitAt(len) match { 
    case (xs, Nil) => other(xs) 
    case (_, _) => op(list) 
} 

而且其复杂性O(len)因此即使列表中,如果长,len是决定性的因素:

if (list.length >= minimumLength) 
    longer(list) 
else 
    shorter(list) 
+1

如果列表真的很长,该怎么办?没有使用长度的匹配/情况会更好... – huynhjl

+5

好点。在这种情况下,你可以使用'lengthCompare'。 –

+0

我不确定“真的很长”可能是什么,但是'Lists'每个元素都有相当大的开销,并且对于非常大的集合没有强烈的指示。他们真的只有一个优点:非常有效的头部/尾部分解。 –

4

您也可以做到这一点。

上述电话op如果list.size < len否则调用other

10

如果你坚持使用模式匹配(也许你想包括更多比赛情况?),你可以使用一个保护条件吧:

list match { 
    case l if(l.size <= 3) => op(l) 
    case l => other(l) 
} 
+2

使用lengthCompare将比较列表长度与3更有效 –