Scala - 使用整数列表作为索引来填充新的数据结构



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

我正在尝试定义一个接受整数列表的函数,例如 List(101, 102, 102, 103, 104)对应于 Items 的类别 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 中是否有更好的方法来获得预期的结果,即通过获取索引列表并使用它来访问列表中的特定项目,其中每个相应项目的两部分元组将"替换"索引以创建新的列表结构?

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

此外,在发布此类问题时,您可能希望提供引用但未定义的元素的界面(相关部分)。什么是"is"(是项吗?),项,类别,属性....,或简化代码以使它们不显示。

现在,问题:

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]。filter不会改变类型,所以仍然Seq[AnyRef],而在map(x =>...)中,x也是一个AnyRef,而不是一个Tuple2,所以它没有_2

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

若要保留类型,通常应执行诸如

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

那将被键入选项[类型的东西],其中类型的东西是你的对。

但是,常规收集有一些更简单的东西。它有点像 match,除了它接受一个分部函数,并且它丢弃了未定义分部函数的元素。

所以那将是

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

假设您已经定义了

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

当你这样做时:

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)列表中剩下的任何内容都必须是元组时。

例如,您可以is.filter(i => t == getId(i.category)),然后再做map,然后你就不需要弄乱列表中的None

最新更新