2011-06-18 9 views
2

私は誰かがScalaで基本的なコードヘルプを私に提供できることを期待していました。私はPythonでいくつかのデモコードを書いた。Scala:再帰的に要素/リストのリストを変更する

要素が整数または他の要素のリストのいずれかを保持できる要素のリストを考えてみましょう。私はこの構造を再帰的に調べて全体の構造を維持しながら変更したいと思います。

これをPythonで表現するために、私は各要素を1つのキー(アイテムの場合は「i」)を持つ辞書にしました。そのキーに対応する値は、intまたは同様のdictのリストです。したがって、

lst = [{'i': 1}, {'i': 2}, {'i': [{'i': 5}, {'i': 6}]}, {'i': 3}] 

def recurse(x): 
    if isinstance(x, list): 
    return [recurse(a) for a in x] 
    else: 
    if isinstance(x['i'], list): 
     return dict(i=[recurse(a) for a in x['i']]) 
    else: 
     return dict(i=(x['i'] + 1)) 

print "Input:" 
for i in lst: 
    print i 
print "\nResult:\n%s" % recurse(lst) 

>>> 
Input: 
{'i': 1} 
{'i': 2} 
{'i': [{'i': 5}, {'i': 6}]} 
{'i': 3} 

Result:  
[{'i': 2}, {'i': 3}, {'i': [{'i': 6}, {'i': 7}]}, {'i': 4}] 

は、私はそれが物事をやって行くには奇妙な方法のビットだ理解が、私は提供されたデータは、そのように構成されています。私は、私の問題は、Pythonが同じ関数から別の型を返すことができるということですが、私はScalaがそれを信じていないと考えています。

はまたレコードに対して、Scalaの要素は... Elemの(4)、またはElemの(リスト(Elemの(3)のように表されるので、私は、パターンマッチングは幾分それに来ることができると仮定する。

+0

あなたは機能を実行したいとは言わないが、私はあなたのpythonコードを読んで見つけ出すつもりはない。 –

+0

私はそれを持っている! –

+0

私は分かりません。あなたは何を達成しようとしていますか?あなたのデータ構造は何ですか? – paradigmatic

答えて

11

I希望。。むしろ、それはこれらのリストが含まれているものを教えてくれないと、リストのリストという呼び出さない構造がツリーがある、唯一の葉のデータがある、より正確には緑豊かなツリーが、それは次のようになります。

sealed trait Tree[+A] 
case class Node[+A](children: Tree[A]*) extends Tree[A] 
case class Leaf[+A](value: A) extends Tree[A] 

次に、メソッドマップを追加して、ツリーの各値に関数を適用します。

sealed trait Tree[+A] { 
    def map[B](f: A => B): Tree[B] 
} 
case class Node[+A](children: Tree[A]*) extends Tree[A] { 
    def map[B](f : A => B) = Node(children.map(_.map(f)): _*) 
} 
case class Leaf[+A](value: A) extends Tree[A] { 
    def map[B](f: A => B) = Leaf(f(value)) 
} 

次に、あなたの入力は次のとおりです。

val input = Node(Leaf(1), Leaf(2), Node(Leaf(5), Leaf(6)), Leaf(3)) 

そして、あなたはあなたが結果表示あなたの出力

を取得input.map(_ + 1)呼び出す場合* [A]ので可変引数木のやや醜いです。ノードを追加することで改善することができますoverride def toString = "Node(" + children.mkString(", ") + ")"

この方法は、クラスの外側でのみ、またはツリー内で直接行うことができます。ここではPythonのように型指定されていない道を作業ツリー

における方法
def map[B](f: A => B): Tree[B] = this match { 
    case Node(children @ _*) => Node(children.map(_.map(f)): _*) 
    case Leaf(v) => Leaf(f(v)) 
} 

などのような非常にスカラ座ではなく、行うことができます。

def recurse(x: Any) : Any = x match { 
    case list : List[_] => list.map(recurse(_)) 
    case value : Int => value + 1 
} 

(リスト内の値を直接置く。あなたのマップ(辞書)のキー「i」は、それを複雑にし、我々はすなわち、チェックすることができませんでしたキャストを強制しなければならないよう力は、コンパイラの警告を受け入れていますケースマップ:マップがキーとして文字列を受け取り地図[文字列、_])


case Elem(content: Any)を使用してはるかに冗長でありながら、直接リスト内の値を入れに比べて余分な安全性を与えないように私に聞こえる、そしてなしそれを木と呼び、節と葉を区別するのが安全ではっきりしていることを示しています。

3

さて、ここでは動作しますが、少し醜い何か:

def make(o: Any) = Map('i' -> o) // m :: Any => Map[Char,Any] 
val lst = List(make(1),make(2),make(List(make(5),make(6))),make(3)) // List[Any] 

def recurce(x: Any): Any = x match { 
    case l: List[_] => l map recurce 
    case m: Map[Char,_] => val a = m('i') 
    a match { 
     case n: Int => make(n + 1) 
     case l: List[_] => make(l map recurce) 
    } 
} 

例:

scala> recurce(lst) 
res9: Any = List(Map((i,2)), Map((i,3)), Map((i,List(Map(i -> 6), Map(i -> 7)))), Map((i,4))) 
+1

確かに。コンパイラがCharを保証することはできないため、Map [Char、_]と一致するとコンパイラ警告が表示されます。しかし、私はそれを避ける方法はないと思う。 –

3

このソリューションは、(多くのタイプセーフですが、木の道を行くに頼ることなく、これは悪い解決策ではありませんが、誰かがすでにそれを作っています:)。これは、intまたはintのリストのいずれかのリストになります。したがって、それは2つのレベルを持つことができます - あなたがもっと望むなら、ツリーを作ってください。

val lst = List(Left(1), Left(2), Right(List(5, 6)), Left(3)) 

def recurse(lst: List[Either[Int, List[Int]]]): List[Either[Int, List[Int]]] = lst match { 
    case Nil => Nil 
    case Left(n) :: tail => Left(n + 1) :: recurse(tail) 
    case Right(l) :: tail => Right(l map (_ + 1)) :: recurse(tail) 
} 
関連する問題