Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala FlatMap提供了错误的结果_Scala_Flatten_Flatmap - Fatal编程技术网

Scala FlatMap提供了错误的结果

Scala FlatMap提供了错误的结果,scala,flatten,flatmap,Scala,Flatten,Flatmap,给定一个文档列表,我希望获得至少共享一个令牌的对。 为了做到这一点,我编写了下面的代码,它通过一个反向索引来实现 object TestFlatMap { case class Document(id : Int, tokens : List[String]) def main(args: Array[String]): Unit = { val documents = List( Document(1, List("A", "B", "C", "D")), D

给定一个文档列表,我希望获得至少共享一个令牌的对。 为了做到这一点,我编写了下面的代码,它通过一个反向索引来实现

object TestFlatMap {
 case class Document(id : Int, tokens : List[String])

 def main(args: Array[String]): Unit = {

   val documents = List(
     Document(1, List("A", "B", "C", "D")),
     Document(2, List("A", "B", "E", "F", "G")),
     Document(3, List("E", "G", "H")),
     Document(4, List("A", "L", "M", "N"))
   )

   val expectedTokensIds = List(("A",1), ("A",2), ("A",4), ("B",1), ("B",2), ("C",1), ("D",1), ("E",2), ("E",3), ("F",2), ("G",2), ("G",3), ("H",3), ("L",4), ("M",4), ("N",4)) //Expected tokens - id tuples
   val expectedCouples = Set((1, 2), (1, 4), (2, 3), (2, 4)) //Expected resulting pairs


   /**
     * For each token returns the id of the documents that contains it
     * */
   val tokensIds = documents.flatMap{ document =>
     document.tokens.map{ token =>
       (token, document.id)
     }
   }

   //Check if the tuples are right
   assert(tokensIds.length == expectedTokensIds.length && tokensIds.intersect(expectedTokensIds).length == expectedTokensIds.length, "Error: tokens-ids not matches")

   //Group the documents by the token
   val docIdsByToken = tokensIds.groupBy(_._1).filter(_._2.size > 1)

   /**
     * For each group of documents generate the pairs
     * */
   val couples = docIdsByToken.map{ case (token, docs) =>
     docs.combinations(2).map{ c =>
       val d1 = c.head._2
       val d2 = c.last._2

       if(d1 < d2){
         (d1, d2)
       }
       else{
         (d2, d1)
       }
     }
   }.flatten.toSet


   /**
     * Same operation, but with flatMap
     * For each group of documents generate the pairs
     * */
   val couples1 = docIdsByToken.flatMap{ case (token, docs) =>
     docs.combinations(2).map{ c =>
       val d1 = c.head._2
       val d2 = c.last._2

       if(d1 < d2){
         (d1, d2)
       }
       else{
         (d2, d1)
       }
     }
   }.toSet

   //The results obtained with flatten pass the test
   assert(couples.size == expectedCouples.size && couples.intersect(expectedCouples).size == expectedCouples.size, "Error: couples not matches")
   //The results obtained with flatMap do not pass the test: they are wrong
   assert(couples1.size == expectedCouples.size && couples1.intersect(expectedCouples).size == expectedCouples.size, "Error: couples1 not matches")
}
对象测试平面图{
案例类文档(id:Int,tokens:List[String])
def main(参数:数组[字符串]):单位={
val文档=列表(
文件(1,清单(“A”、“B”、“C”、“D”),
文件(2,清单(“A”、“B”、“E”、“F”、“G”),
文件(3,清单(“E”、“G”、“H”),
文件(4,列表(“A”、“L”、“M”、“N”))
)
val expectedTokensIds=List((“A”,1),(“A”,2),(“A”,4),(“B”,1),(“B”,2),(“C”,1),(“D”,1),(“E”,2),(“E”,3),(“F”,2),(“G”,2),(“G”,3),(“H”,3),(“L”,4),(“M”,4),(“N”,4))//预期的标记-id元组
val expectedCouples=Set((1,2)、(1,4)、(2,3)、(2,4))//预期的结果对
/**
*For each标记返回包含它的文档的id
* */
val tokensIds=documents.flatMap{document=>
document.tokens.map{token=>
(令牌,document.id)
}
}
//检查元组是否正确
断言(tokensIds.length==expectedTokensIds.length&&tokensIds.intersect(expectedTokensIds.length==expectedTokensIds.length,“错误:令牌ID不匹配”)
//按令牌对文档进行分组
val docIdsByToken=tokensIds.groupBy(u._1).filter(u._2.size>1)
/**
*为每组文档生成对
* */
val couples=docIdsByToken.map{case(token,docs)=>
docs.combinations(2).map{c=>
val d1=中心压头。\u 2
val d2=最后一次
如果(d1
docs.combinations(2).map{c=>
val d1=中心压头。\u 2
val d2=最后一次
如果(d1
问题是应该生成最终结果的flatMap不能正常工作,它只返回两对:(2,3)和(1,2)。 我不明白为什么它不起作用,而且IntelliJ建议我使用flatMap,而不是使用map然后展平

有人能告诉我问题出在哪里?因为我搞不清楚,我过去也有过这个问题

谢谢


Luca

这是一个很好的例子,证明了如果在
map
/
flatMap
/
flattle
期间在不同类型的集合之间切换,那么所有的尼斯单子定律都不一定成立


您必须将
映射
转换为
列表
,以便在构建另一个
映射
作为中间结果时不会重复覆盖键,因为
映射
将覆盖键,而不是收集所有对:

val couples1 = docIdsByToken.toList.flatMap{ case (token, docs) =>
  docs.combinations(2).map{ c =>
    val d1 = c.head._2
    val d2 = c.last._2

    if(d1 < d2){
      (d1, d2)
    }
    else{
      (d2, d1)
    }
  }
}.toSet
它将生成
Set((2,1)、(2,3))
,而不是
Set((2,3))
,因为 在
flatMap
之后和
toSet
之前,中间结果是一个新的
Map
,该Map只能为
key=2
保存一个值


与第一个版本不同的是,在
map
之后,您将获得类似于
Iterable[List[(Int,Int)]]
的东西,它不是
map
,因此不能丢失/覆盖任何键。

令牌
从未被引用。这更有意义:
val-couples1=docIdsByToken.values.flatMap{docs=>
..@jwvh我复制了一段经过编译、测试的代码(至少从表面上看,是通过目视检查输出的),并通过了OP提供的所有断言。该标记不应该被引用,它只充当数字之间的粘合剂。一旦找到数字对,字符串标记可以被丢弃。但它应该被和下划线替换。我保留它以尽可能多地保留原代码。这是最糟糕的情况之一Scala当前收藏库的“功能”。由于映射
Set
Map
,我有很多错误。你可以看看我曾经问过的关于这个问题的问题。@ziggystar问得好,但由于某些原因,我对解决方法没有印象。老实说,希望有更系统的东西:]
val m = Map("A" -> (2, 1), "B" -> (2, 3))
val s = m.flatMap{ case (k, v) => List(v) }.toSet
println(s)