2

特定の文字のネストされた文字配列を検索し、配列から文字のインデックスを返そうとしています。

コードスニペット

def search(target: Char, arr:Array[Array[Char]]): List[Int] = {
    for (i <- 0 until arr.length) { //search through first layer of array
    for (j <- 0 until arr(i).length) { //search through second layer of array
        if (arr(i)(j) == target) {
            val x = List(i,j)
            return x
        } }}}

ただし、コンパイルからエラーが発生します。これは、この関数が2つの型シグネチャを返していることを示しています。エラーメッセージ:

error: type mismatch;
 found   : Unit
 required: List[Int]
for (i <- 0 until arr.length) { //search through first layer of array
       ^

ここで 2 つの同様のスレッドを見つけました。エラーが明らかでないのはなぜですか?見つかった: 必要な単位: Int - これを修正するにはどうすればよいですか ?

しかし、彼らは私が直面している問題を解決しません:リストを返そうとしていますが、コンパイラは for ループでスタックしています..

4

5 に答える 5

4

すでに多くの回答があるようですが、これが問題にアプローチする最も慣用的な方法だと思います。

コード

def search(target: Char, arr: Array[Array[Char]]): List[(Int, Int)] = {

    val indices = for{
        (a, i) <- arr.iterator.zipWithIndex
        (c, j) <- a.iterator.zipWithIndex
        if( c == target )
    } yield i -> j

    indices.toList

}

説明

x <- yscala では、for 内包表記はネスト可能であるため、別の行を追加するだけで、ネストされた配列の程度に関係なく処理できます。if内のステートメントでフィルタリングを導入できますfor{...}

内包表記では、aは 内のi番目の配列でarriは最初のインデックスです。cj内の 番目の文字でajは 2 番目のインデックスです。for-comprehension のために舞台裏で配列をコピーする必要なく、その場で評価できるようiteratorに使用します。indices最後に、イテレータtoListの結果をリストに評価するために呼び出します。indices

戻り値の型List[(Int, Int)]は、ペアのリストです。ターゲットをとList( (1,2), (3,4) )で見つけた場合は、戻るよりも戻る方が理にかなっています。i=1, j=2i=3, j=4List(1,2,3,4)

一般的な考え

returnscala での使用は避けてください。toList通常は、yield を使用して反復子のようなアプローチでコレクションを処理し、またはtoMapまたはを呼び出して結果を評価できtoWhateverます。

scala コレクション API は、これらの多くの場合にも非常に役立ちます。条件に一致する最初の項目だけが必要な場合は、 を使用できますmyCollection.find(...)。scala docs を調べて、すでに利用可能な便利な関数の膨大な種類を確認してください。

于 2013-02-03T15:54:50.130 に答える
1

2次元配列内の要素の最初のインデックスを見つけるための私の解決策は次のとおりです:(すべてのインデックスを見つけたい場合は、collectFirtをcollectに置き換えてください)

def search[T](target: T, arr: Array[Array[T]]): List[Int] = 
  arr.indices.collectFirst{
    case k if arr(k).contains(target) => 
      List(k, arr(k).indexWhere(_ == target)) 
  }.getOrElse(Nil)

テスト:

scala> val t = Array(
     |     Array('a', 'b', 'c'),
     |     Array('b'), 
     |     Array('c', 'a'),
     |     Array('a', 'a', 'x', 'a')
     | )

scala> println(search('a', t))
List(0, 0)

scala> println(search('x', t))
List(3, 2)

scala> println(search('e', t))
List()
于 2013-02-03T14:18:28.927 に答える
1

Java にあまり似ていないアプローチを全体的に使用することをお勧めします。あなたの関数が何をすべきか完全にはわかりませんが、ネストされた配列内の一致のすべての (x, y) インデックスのリストが必要な場合は、次のようにすることができます:

def search(target: Char, array: Array[Array[Char]]): Seq[(Int, Int)] = {
  array.zipWithIndex.filter(_._1.contains(target)).map { xa =>
    xa._1.zipWithIndex.filter(_._1 == target).map(xb => (xa._2, xb._2)).toSeq
  }.flatten.toSeq
}

次のように動作します。

val t = Array(
    Array('a', 'b', 'c'), 
    Array('b'), Array('c', 'a'), 
    Array('a', 'a', 'x', 'a')
)
println(search('a', t))
=> ((0,0), (2,1), (3,0), (3,1), (3,3))
于 2013-02-03T13:46:09.947 に答える
0

2 番目の配列が空の場合、または if 式が false と評価される場合、for ループ自体は Unit を返します。if 式の後のコードに到達しない場合は null を返すように書き直すことができます。

x の割り当ても省略しますが、実際には意味がありません。

  def search(target: Char, arr:Array[Array[Char]]): List[Int] = 
  {
    for (i <- 0 until arr.length) 
    { //search through first layer of array
      for (j <- 0 until arr(i).length) 
      { //search through second layer of array
        if (arr(i)(j) == target) 
        {
          return List(i,j)
        } 
      }
    }
    Nil
  }

ところで、これはおそらくより機能的なアプローチで書き直すことができますが、それはこの質問の範囲を超えています。

于 2013-02-03T13:11:10.727 に答える
0

You only return a List if a particular condition is met (arr(i)(j) == target). You have to define a return value for the case that the for comprehensions run through. E.g.

def search(target: Char, arr:Array[Array[Char]]): List[Int] = {
  for (i <- 0 until arr.length) { //search through first layer of array
    for (j <- 0 until arr(i).length) { //search through second layer of array
      if (arr(i)(j) == target) {
        val x = List(i,j)
        return x
      }
    }
  }
  Nil  // not found
}
于 2013-02-03T13:10:30.297 に答える