【问题标题】:Scala - using a list of ints as an index to populate a new data structureScala - 使用整数列表作为索引来填充新的数据结构
【发布时间】:2015-01-03 22:20:55
【问题描述】:

我有一个对象列表(在本例中为项目),它们具有类别 ID 和属性(它本身是自定义类型的列表)。

我正在尝试定义一个接受整数列表的函数,例如List(101, 102, 102, 103, 104) 对应于项目的类别 ID,并创建一个元组列表,其中包括类别类型(这是一个选项)和每个类别的属性列表中的每个属性类型。到目前为止,我有以下内容,但我收到value _2 is not a member of Product with Serializable 的错误。

def idxToData(index: List[Int], items: Seq[Item]): List[(Option[Category], Property[_])] = {

  def getId(ic: Option[Category]): Int => {
   ic match {
     case Some(e) => e._id
     case None => 0
    }
  }

  index.flatMap(t => items.map(i => if(t == getId(i.category)){
    (i.category, i.properties.list.map(_.property).toList.sortWith(_._id < _._id))
  } else {
    None
  }.filter(_ != None )
  ))
   .map(x => x._2.map(d => (x._1, d)))
   .toList
}

我不确定它是如何分配该类型的(我当时假设我应该有一个我正在尝试映射的元组列表)。

总体而言,在 scala 中是否有更好的方法来获取所需的结果,即通过获取索引列表并使用它来访问列表中的特定项目,其中每个对应项目的两个部分的元组将“替换”索引来创建新的列表结构?

【问题讨论】:

  • 那里有点纠结。您是否有机会将某些功能提取到本地 def 中(然后查看问题是否仍然存在)?如果编译器已编译,编译器可能还会告诉您其他令人担忧的方面(例如,case None 呢?)。如果您只想对从元素计算的内容进行常规排序,则可以使用 sortBy 作为速记。 (sortBy(_.foo)sortWith(_.foo &lt; _.foo) 相同)。
  • @RexKerr 是的,这有点纠结,我还在用 scala 和 fp 来解决问题。我至少将 match 语句拉到它自己的本地 def 中,并添加了 None 发送回 0 的案例。它似乎仍然与 Product of Serializable 一起存在 - 不知道为什么。

标签: list scala dictionary indexing


【解决方案1】:

你应该拆分你的代码,给事物命名(添加一些 vals 和一些 defs),当编译器不同意你的时候,写类型,这样编译器会尽早告诉你它不同意的地方(不要担心,我们都是从 FP 开始的时候这样做的)

此外,在发布此类问题时,您可能希望提供(相关部分)被引用但未定义的元素的接口。什么是“是”(是项目吗?)、项目、类别、属性......,或者简化你的代码,使它们不出现。

现在,问题来了:

if(t == (i.category match { case Some(e) => e._id})){
   (i.category, i.properties.list.map(_.property).toList.sortWith(_._id < _._id))
} else {
  None
}

第一个分支是 Tuple2(Int, 不管) 类型,而第二个分支是完全不相关的类型 None。显然,没有比AnyRef 更好的通用超类型,所以这就是 if 表达式的类型。那么 is.map 的类型(假设is 是某种Seq)将是Seq[AnyRef]。过滤器不改变类型,所以还是Seq[AnyRef],在map(x =&gt;...)中,x也是AnyRef,不是Tuple2,所以它没有_2

当然,列表实际上只包含元组,因为最初它有元组和无,而你已经删除了无。但是当它输入AnyRef 时,编译器就丢失了。 (正如编译器错误消息所告诉和 Imm 所指出的那样,编译器会找到比 AnyRefProduct with Serializable 稍微更精确的类型;但是,这对您没有任何好处,所有有用的类型信息仍然丢失在那里)。

要保留类型,通常您应该执行以下操作

if(....) {
   Some(stuff)
else
   None

那应该是 Option[type of stuff],其中 type of stuff 就是你的 Pair。

但是,例行收集有一些更简单的东西。 它有点像 match,除了它需要一个偏函数,并且它会丢弃未定义偏函数的元素。

原来如此

is.collect { case i if categoryId(i) == Some(t) => 
   (i.catetory, i.properties....)
}

假设你已经定义了

def categoryId(item: Item): Option[Int] = item.category.map(._id)

【讨论】:

    【解决方案2】:

    当你这样做时:

    is.map(i => if(t == getId(i.category)){
      (i.category, i.properties.list.map(_.property).toList.sortWith(_._id < _._id))
    } else {
      None
    }
    

    你得到一个List[Product with Serializable](你应该得到一个类型错误,但这可能是一个很长的题外话),因为这是None(Category, List[Property[_]]) 或任何元组类型的唯一超类型。编译器不够聪明,无法携带联合类型并找出当您 filter(_ != None) 时,列表中剩下的任何内容都必须是元组。

    尝试改写这部分。例如。您可以在map 之前执行is.filter(i =&gt; t == getId(i.category)) 首先,然后您就不需要在列表中使用Nones。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-04
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-05
      相关资源
      最近更新 更多