有条件后如何删除数组中的每个元素?

时间:2019-02-09 23:01:20

标签: arrays scala list

所以我在Scala中有一个字符串数组,称为发音数组,如下所示:

["EH1","N", "D", "P", "ER0", "EH1", "N", "TH", "AH0", "S", "IY2", "Z"]

并且我想编写一条if else语句,该语句以相反的方式读取数组,并且一旦找到其中包含数字的字符串,它就会删除之后的所有字符串,或者将之前的所有内容放入一个单独的数组中。 / p>

因此,对于上面的示例,id希望其在“ IY2”处停止,然后仅使用[“ IY2”,“ Z”]创建一个新数组,或者删除之后的每个字符串并保留原​​始数组,例如I说,[“ IY2”,“ Z”]。数字本身不是整数btw,它是字符串的一部分,数字范围为0-2。

我已经尝试过使用if来查找数字0、1、2的反向循环,但是它返回每个带有数字的字符串,因此它返回[IY2,AH0,EH1,ER0,EH1],但没有找到第一个带数字的字符串后立即停止。而且,即使我找到了停止它的方法,我也不知道如何将字符串之前的所有内容放入新数组中。

for (sounds <- pronunciationArray.reverse) {

  val number0 = sounds.contains("0")

  if (number0 == true) {

    println(sounds)

  } else if (number0 == true){

    println(sounds)

  } else if (number1 == true){

    println(sounds)

  } else {

    -1

  }

}

我希望它只返回[“ IY2”,“ Z”],但它返回[IY2,AH0,EH1,ER0,EH1]

3 个答案:

答案 0 :(得分:1)

我对您的目标尚不完全清楚,但是... match t.x with | None -> failwith "invariant for foo violated in bar” | Some x -> (* carry on *) ... (* don’t do this *) type 'a one_or_two = 'a option * 'a option ... let (first, second) = ... : _ one_or_two in match first with | None -> (* now we know second must be Some *) let second = extract_x second in ... (* do this instead *) type 'a one_or_two = First of 'a | Second of 'a | Both of 'a * 'a 有一个Array函数可根据条件将其分为两部分-第一部分是数组的前缀,其中所有内容满足条件,第二部分是剩余部分。

比方说,您的条件是字符串包含span而不是数字(只是因为我很懒-它可以是任何函数2)。如果我们反转数组,然后对函数的 negation 进行拆分,则会得到:

f: String => Boolean

我们知道第二个数组的第一个元素满足我们的条件,因此我们可以组装结果:

scala> a.reverse.span(!_.contains("2"))
res5: (Array[String], Array[String]) = (Array(Z),Array(IY2, S, AH0, TH, N, EH1, ER0, P, D, N, EH1))

所有倒车也许不是最有效的,但可以完成工作。

答案 1 :(得分:1)

可以解决的一种算法是

  • 从元素具有0、1或2的最后一个元素开始查找元素的索引
  • 在上面的索引处拆分数组
  • 获取第一个数组的最后一个元素和整个第二个数组

示例

val pronunciationArray = Array("EH1","N", "D", "P", "ER0", "EH1", "N", "TH", "AH0", "S", "IY2", "Z")

def takeUntil(inputArray: Array[String], condition: String => Boolean): Array[String] = {
  val findIndexFromLast = inputArray.reverse.zipWithIndex.collectFirst {
    case (elem, index) if condition.apply(elem) => index
  }

  findIndexFromLast match { // pattern match to check if there exists element with 0, 1, or 2
    case Some(indexFromLast) =>
      inputArray.splitAt(inputArray.length - indexFromLast) match {
        case (head, tail) => head.last +: tail
      }
    case None => // no element with 0, 1, 2 exists
      inputArray
  }
}

takeUntil(
  inputArray = pronunciationArray,
  condition = elem => elem.contains("0") || elem.contains("1") || elem.contains("2")) //gives [IY2, Z]

使用.span(predicate)解决问题的另一种方法是.splitAt(index)的更好版本

def takeUntil2(inputArray: Array[String]): Array[String] = {
  inputArray.reverse.span {
    element =>
      !element.contains("0") && !element.contains("1") && !element.contains("2")
  } match {
    case (head, tail) => tail.take(1) ++ head.reverse
  }
}

val result = takeUntil2(inputArray = pronunciationArray)

现在,使用scala方法,您可以扩展Array以具有自定义功能,

  implicit class ArrayOps(array: Array[String]) {
    def takeUntil(predicate: String => Boolean): Array[String] = {
      val splitAt = array.reverse.span(predicate.apply)
      splitAt._2.take(1) ++ splitAt._1.reverse
    }
  }

  val res = pronunciationArray
    .takeUntil(predicate = elem => !elem.contains("0") && !elem.contains("1") && !elem.contains("2"))

类似的问题: How to implement 'takeUntil' of a list?

How do I pattern match arrays in Scala?

答案 2 :(得分:0)

Scala数组提供了一个lastIndexWhere方法,该方法采用一个谓词,并返回满足该谓词的最后一个元素的索引:

val arr = Array("EH1","N", "D", "P", "ER0", "EH1", "N", "TH", "AH0", "S", "IY2", "Z")

val idx = arr.lastIndexWhere(e => e.intersect(Array('0', '1', '2')).size > 0)

然后调用takeRight方法以获得所需的结果

val res = arr.takeRight(arr.size - idx)