2015-10-21 10 views
7

いくつかのネストされたケースクラスとフィールドaddressesSeq[Address]です:"Seq"フィールドでこのネストされたケースクラスを変更するにはどうすればいいですか?

val employee = Employee(Company(Seq(
    Address(Street("aaa street")), 
    Address(Street("bbb street")), 
    Address(Street("bpp street"))))) 

それは3つのアドレスを持っている:

// ... means other fields 
case class Street(name: String, ...) 
case class Address(street: Street, ...) 
case class Company(addresses: Seq[Address], ...) 
case class Employee(company: Company, ...) 

私は従業員を持っています。

そして、私は通りを「b」だけで始めることを大切にしたいと思います。私のコードは次のように混乱している:

val modified = employee.copy(company = employee.company.copy(addresses = 
    employee.company.addresses.map { address => 
     address.copy(street = address.street.copy(name = { 
      if (address.street.name.startsWith("b")) { 
      address.street.name.capitalize 
      } else { 
      address.street.name 
      } 
     })) 
     })) 

modified従業員は次のようになります。私はそれを改善する方法を探していて、ものを見つけることができません

Employee(Company(List(
    Address(Street(aaa street)), 
    Address(Street(Bbb street)), 
    Address(Street(Bpp street))))) 

Monocleでも試しましたが、この問題には適用できません。

これを改善する方法はありますか?


PS:二つの重要な要件があります。

  1. 使用のみ不変データは
  2. あなたがaddressesでの交換に開いている場合は、他の既存のフィールド

答えて

13

ピーターNeyensが指摘するように、型崩れのSYBがうまくここで実際に動作するが、それは必ずしもかもしれツリー内のすべてStreetの値を変更しますあなたが望むものになります。あなたは、パスをより詳細に制御する必要がある場合は、モノクルは助けることができる:ジュリアン・トリュフォーが編集中で指摘するように

import monocle.Traversal 
import monocle.function.all._, monocle.macros._, monocle.std.list._ 

val employeeStreetNameLens: Traversal[Employee, String] = 
    GenLens[Employee](_.company).composeTraversal(
    GenLens[Company](_.addresses) 
     .composeTraversal(each) 
     .composeLens(GenLens[Address](_.street)) 
     .composeLens(GenLens[Street](_.name)) 
) 

    val capitalizer = employeeStreeNameLens.modify { 
    case s if s.startsWith("b") => s.capitalize 
    case s => s 
    } 

を、あなたは、レンズににすべての方法を作成することで、これは、より簡潔な(しかし、あまり一般的な)を作ることができます通りの名前の最初の文字:

import monocle.std.string._ 

val employeeStreetNameFirstLens: Traversal[Employee, Char] = 
    GenLens[Employee](_.company.addresses) 
    .composeTraversal(each) 
    .composeLens(GenLens[Address](_.street.name)) 
    .composeOptional(headOption) 

val capitalizer = employeeStreetNameFirstLens.modify { 
    case 'b' => 'B' 
    case s => s 
} 

あり、もう少し簡潔な上記の定義になるだろうシンボリック演算子はありますが、私は非シンボリックバージョンを好みます。

そして、(明確にするために再フォーマット結果):

scala> capitalizer(employee) 
res3: Employee = Employee(
    Company(
    List(
     Address(Street(aaa street)), 
     Address(Street(Bbb street)), 
     Address(Street(Bpp street)) 
    ) 
) 
) 

注型崩れの答えのように、あなたがList代わりのSeqを使用するようにEmployee定義を変更する必要がある、またはあなたドン場合だろうということあなたのモデルを変更したい場合は、Iso[Seq[A], List[A]]Lensにその変換を組み込むことができます。

8

を失うことはありません。 CompanySeqからListまで、「スクラップYour Boilerplate」は形のないもの(example)。

import shapeless._, poly._ 

case class Street(name: String) 
case class Address(street: Street) 
case class Company(addresses: List[Address]) 
case class Employee(company: Company) 

val employee = Employee(Company(List(
    Address(Street("aaa street")), 
    Address(Street("bbb street")), 
    Address(Street("bpp street"))))) 

は、名前が「B」で始まる場合Streetの名前を大文字多様関数を作成することができます。

あなたがとして使用することができます
object capitalizeStreet extends ->(
    (s: Street) => { 
    val name = if (s.name.startsWith("b")) s.name.capitalize else s.name 
    Street(name) 
    } 
) 

val afterCapitalize = everywhere(capitalizeStreet)(employee) 
// Employee(Company(List(
// Address(Street(aaa street)), 
// Address(Street(Bbb street)), 
// Address(Street(Bpp street))))) 
+1

のように本当にありがとうございましたが、それを行うことができます!かっこいい。私は最終的にどのように強力な形がないのかを知る機会を得ました! – Freewind

+3

良い答えですが、私の警告を見てください(これはデータ構造の_any_通り名を変換します)。 –

2

quicklens

を見てみましょうあなたはこの

import com.softwaremill.quicklens._ 

case class Street(name: String) 
case class Address(street: Street) 
case class Company(address: Seq[Address]) 
case class Employee(company: Company) 
object Foo { 
    def foo(e: Employee) = { 
    modify(e)(_.company.address.each.street.name).using { 
     case name if name.startsWith("b") => name.capitalize 
     case name => name 
    } 
    } 
} 
関連する問題