【问题标题】:Scala - Creating a new list by combining the contents of one list and the hierarchy of anotherScala - 通过组合一个列表的内容和另一个列表的层次结构来创建一个新列表
【发布时间】:2020-01-08 17:41:07
【问题描述】:

我正在尝试创建一个新列表,它将一个单级列表的内容与另一个嵌套列表的层次结构相结合,并通过两个列表中对象的 ID 将它们链接起来。注意:BChain 对象的 ID 存储在其中的 ItemObj 中。

我有三个对象:

ItemObj(id: String, stored: DateTime)
BChain(item: ItemObj, List[BChain])
AChain(aid: String, List[AChain])

我有两个列表:

val nestedList: List[AChain]
val singleLevelList: List[BChain]

我希望第二个列表具有第一个列表的层次结构,但仍包含它自己的元素。因此,BChain 在放入新需要的列表输出时,应该包括原始的ItemObjList[BChain] 属性(包括ItemObj 的所有原始属性数据-ID 和DateTime)。

所以代替(输入):

 val nestedList = List(
 AChain("123", List(AChain("456", [])),
 AChain("789", [])
)

val singleLevelList = List(
 BChain(ItemObj("123", DateTime), []),
 BChain(ItemObj("456", DateTime), []),
 BChain(ItemObj("789", DateTime), []))
)

我想要以下输出:

val combinedLists = List(
     BChain(ItemObj("123", DateTime), List(BChain(ItemObj("456", DateTime), [])),
     BChain(ItemObj("789", DateTime), [])
)

作为最终名单。

注意:嵌套列表中的项目可能比单级列表中的项目多,如果是这种情况,则应忽略额外的项目。单级列表中的每一项都应对应于嵌套列表中的一项。

我怎样才能做到这一点?

任何帮助将不胜感激。

【问题讨论】:

  • @LuisMiguelMejíaSuárez 我已经编辑了我的问题。
  • 任务不清楚,因为输出中的combinedList与输入中的nestedList相同,所以除了将AChain更改为BChain包装器之外,对于nestedList应该进行什么样的操作并不明显。如果在某些情况下应该忽略某些内容,请提供此示例
  • 不一样。对象不同。为简单起见,我省略了对象属性。这是两个完全不同的对象,它们共享相同的 ID 值。 nestedListAChain 的嵌套列表。 combinedListsBChain 的嵌套列表,其中BChain 对象取自singleLevelListBChain 对象。
  • 所以在输出中您只想重复nestedList 的层次结构但使用singleLevelList 对象?
  • 组合列表是第一个列表与第二个列表内容的层次结构(因此没有AChain对象)

标签: list scala nested


【解决方案1】:

首先我必须模拟一个 DateTime 类型和值,以便编译以下内容。

case class ItemObj(id: String, stored: DateTime)
case class BChain(item: ItemObj, bcl :List[BChain])
case class AChain(aid: String, acl :List[AChain])

然后我将您的 singleLevelList 更改为真正的 Scala 代码并创建了一个 Map 以便快速查找。

val singleLevelList = List(
  BChain(ItemObj("123", DateTime), Nil),
  BChain(ItemObj("456", DateTime), Nil),
  BChain(ItemObj("789", DateTime), Nil)
)

val sLLMap = singleLevelList.groupBy(_.item.id)

接下来使用递归方法将所有AChains 更改为BChains。

def a2b(aLst :List[AChain]) :List[BChain] =
  aLst.map(a => BChain(sLLMap(a.aid).head.item, a2b(a.acl)))

现在来测试一下。

val nestedList = List(
  AChain("123", List(AChain("456", Nil))),
  AChain("789", Nil)
)

a2b(nestedList)  //appears to work

当然,如果nestedList 有一个 A 而singleLevelList 中没有对应的 B,这将抛出。

【讨论】:

  • stored 属性已存在于 ItemObj 中。我将如何携带它或进行某种 BChain 复制并仅更新 bcl
  • 我听不懂你的问题。把什么带到哪里去? storedItemObj 的一部分,它被完整地复制到新结构中。 singleLevelList 中的原始bcl 值不会被复制,因为nestedList 的结构决定了新的bcl 值。
  • 对不起,我没有意识到已经添加了评论,我对存储的属性感到困惑,但我误解了你为什么要创建虚拟值。我现在正在尝试您的解决方案,它似乎应该可以正常工作。我会尽快更新你。感谢您的帮助。
  • 有一个问题。创建sLLMap 时,它会更改 ID 的顺序(不使用示例数据,而是从 DB 获取的数据 - 相同的结构/类型),这意味着 sLL 中的两个内部 BChain 与 sLL 中的两个内部 AChain 的顺序不同nL。这是一个问题,因为它现在无法在特定点找到 ID 并导致 key not found 异常。有什么办法可以避免这种情况?
  • 我已经通过辅助对每个级别的nestedList 进行了排序,但我仍然遇到同样的问题。如果我找到解决方案,我会更新。
【解决方案2】:

也许你想要这样的东西?

final case class ItemObj(id: String, stored: DateTime)
final case class BChain(item: ItemObj, list: List[BChain])
final case class AChain(aid: String, list: List[AChain])

def combine(as: List[AChain], bs: List[BChain]): List[BChain] = {
  val asMap = as.iterator.map(a => a.aid -> a.list).toMap

  def toBChain(a: AChain): BChain =
    BChain(
      item = ItemObj(id = a.aid, stored = ???),
      list = a.list.map(toBChain)
    )

  bs.map {
    case BChain(item, list) =>
      val newElements =
        asMap
          .getOrElse(key = item.id, default = Nil)
          .map(toBChain)

      BChain(
        item,
        list ::: newElements
      )
  }
}

【讨论】:

  • 您能否更改您的解决方案以解决我在问题中错误省略的内容? BChain 对象实际上是BChain(ItemObj, List[BChain])。我需要的 BChain 的 ID 实际上在 Bchain 中的ItemObj 上。所以...final case class ItemObj(id: String, stored:DateTime)final case class BChain( item: ItemObj, listL List[BChain])AChain() 类是正确的,但我忘记了关于 ItemObj 的重要细节
  • 我会更新我的问题。抱歉,我意识到这会使事情变得更加复杂。
  • @Chris 我更新了我的答案,现在的问题是你将如何创建所有嵌套 BChainsstored 字段?与根的值相同?
  • 我希望继承 ItemObj 中已经存在的 stored 属性。它不应该再次创建。感谢您的帮助
  • @Chris 所以你的意思是嵌套的 BItems 不应该保留它们 AItems 的原始 ID,而是使用相同的 ItemObj?如果你能明确你的问题,显示许多输入和预期输出并使用正确的 scala 语法,那就更好了。
【解决方案3】:

即使嵌套列表的根元素在单级列表中不存在,此代码也将起作用

final case class ItemObj(id: String, stored: DateTime = null)
final case class AChain(aid: String, children: List[AChain] = List())
final case class BChain(bid: ItemObj, children: List[BChain] = List())

val nestedList = List(
  AChain("123", List(AChain("456"))),
  AChain("789")
)

def getCombineList(nestedList: List[AChain], singleList: List[BChain]): List[BChain] = {
  val singleListMap = singleList.groupBy(_.bid.id)

  def combine(items: List[AChain]): List[BChain] = {
    items flatMap {item => 
      val children = combine(item.children)
      val parent = singleListMap.get(item.aid).map(v =>
        List(v.head.copy(children = children))
      ).getOrElse(
        children
      )
      parent
    }
  }

  combine(nestedList)
}

val s = getCombineList(nestedList, List(BChain(ItemObj("456")), BChain(ItemObj("789"))))

【讨论】:

  • 我更新了我的问题,增加了一层复杂性。有关简要说明,请参阅上面的评论。抱歉让事情复杂化了。无论如何,我感谢您的帮助。如果您可以更新您的答案以适应BChain 内的ItemObj,那就太好了。但是,如果您没有时间,那也没关系,无论如何,谢谢!
  • 没问题,只是稍作改动。请检查我的更新
  • @Chris,检查您是否有与我相同的案例类属性名称...如果没有,请更正代码
  • 啊,是的,对不起。我的财产名称错误。但是,我现在在children = children 处得到一个类型不匹配,说它需要一个“ItemObj”,但找到了一个List[RuleChain]。它可能是另一个属性名称。为了更清楚,我需要给它们命名。
  • @Chris,请照原样复制我的代码以进行检查,它运行良好,然后根据您的姓名进行编辑
猜你喜欢
  • 2017-09-18
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 2016-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多