Estoy intentando devolver un mapa en scala. Aquí está mi código:

    val interestRegEx = """(\w+) Interests \((.+ Interest)\)""".r
    val singleAttributes = Seq("Sport Interests (Some Interest):Running,Swimming","Something else:True")
    val interests = singleAttributes.map { x =>
      // e.g. ("Sport Interests (Some Interest)", "Running,Swimming") should
      // result in ("Sport Running" -> "Some Interest", "Sport Swimming" -> "Some Interest")
      val attVal = x.split(':')

      attVal(0) match {
        case interestRegEx(interestProduct, interestAmount) =>
          Some(attVal(1).split(",").map { i =>
            Map(s"$interestProduct $i" -> interestAmount)
          }.reduce(_ ++ _))
        case _ => None
      }
    }.fold(Map[String, String]())(_) //.reduce(_ + _)

El problema es intentar reducir la colección a un solo mapa [cadena, cadena]. Pensé que el pliegue podría funcionar, pero como no lo hace, quizás incluso necesite agregar un reduce(_ + _) después, pero eso tampoco funciona.

La parte que no entiendo es que IntelliJ me dice que interests tiene el tipo ((Equals, Equals) => Equals) => Equals. WTF? ¿De dónde provienen estos Equals y por qué no se trata simplemente de agregar todos los mapas para devolver un mapa que contenga todas las claves y valores?

1
jbrown 9 feb. 2015 a las 13:37

2 respuestas

La mejor respuesta

Si simplificamos su ejemplo, obtendremos:

  val interests = Seq[String]().map { x =>
    Option[Map[String, String]](Map("k" -> "v"))
  }.fold(Map[String, String]())(_)

Esto significa que estamos intentando fold Seq[Option[Map[String, String]]] con el valor inicial Map[String, String]():

def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 = foldLeft(z)(op)

De la definición de fold podemos ver que el compilador espera que Option[Map[String, String]] (cada valor en el plegado) y Map[String, String] (valor de inicialización) sean del mismo tipo.

Si inspecciona la jerarquía Option, verá:

Option -> Product -> Equals

Para Map tenemos lo siguiente:

Map -> GenMap -> GenMapLike -> Equals (la jerarquía de rasgos es complicada, puede haber otras cadenas).

Entonces podemos ver que el tipo común más cercano es Equals.

La segunda parte de tu rompecabezas es (_).

El compilador lo trata como un argumento de lambda:

val interests = x => /*omited*/.fold(Map[String, String]())(x)

Como vimos, x es (A1, A1) => A1. Y en nuestro caso es:

(Equals, Equals) => Equals

El resultado de fold es A1 que también es Equals.

Como resultado, el tipo lambda es:

((Equals, Equals) => Equals) /*<< arg*/ => /*result >>*/ Equals

ACTUALIZACIÓN:

Para resolver su problema, creo que debería usar:

.flatten.reduce(_ ++ _)
2
user5102379 9 feb. 2015 a las 11:54

Cuando obtienes un rasgo como Product o Equals como el tipo inferido de una declaración, generalmente puedes apostar que tienes una falta de coincidencia de tipos en alguna función de orden superior. Por lo general, no obtiene Any o AnyRef porque eso solo ocurre si algún conjunto de tipos tiene nada en común. Una cosa que me llama la atención es que su segundo argumento para fold solo toma un parámetro. Sorprendentemente, ese tipo comprueba, pero probablemente sea lo que le dé los tipos que no espera.

Creo que lo que querías hacer es algo más como:

val interestRegEx = """(\w+) Interests \((.+ Interest)\)""".r
val singleAttributes = Seq("Sport Interests (Some Interest):Running,Swimming","Something else:True")
val interests = singleAttributes.map { x =>
  // e.g. ("Sport Interests (Some Interest)", "Running,Swimming") should
  // result in ("Sport Running" -> "Some Interest", "Sport Swimming" -> "Some Interest")
  val attVal = x.split(':')

  attVal(0) match {
    case interestRegEx(interestProduct, interestAmount) =>
      attVal(1).split(",").map { i =>
        Map(s"$interestProduct $i" -> interestAmount)
      }.reduce(_ ++ _)
    case _ => Map.empty
  }
}.reduce(_ ++ _)

Para esto obtuve:

scala> interests
res0: scala.collection.immutable.Map[_ <: String, String] = Map(Sport Running -> Some Interest, Sport Swimming -> Some Interest)

Me deshice de las Option que envuelven las Map s en su coincidencia de expresiones regulares. Ya que está planeando combinar los mapas, también puede usar el mapa vacío como su caso de no coincidencia. Luego usé reduce en lugar de fold para tu partido final, tal como lo habías hecho en el map interno.

1
acjay 9 feb. 2015 a las 11:52